Why I Built Official SDKs for the snapWONDERS API

Updated 16 August 2026: Part of this article is out of date. Five days after it was published, snapWONDERS added a direct single-POST upload for files under 95 MB, so the TUS choreography described below is no longer the only way in. The story stands as written — one paragraph of guidance has been corrected, and there’s an update at the end explaining what changed and why.

The snapWONDERS API has been open for a while — forensic analysis, format conversion, and snapWONDERS Vaultify’s steganography, all reachable over HTTPS and described by a published OpenAPI 3.x specification. Several developers reached out about integrating it, and the same nuance kept coming up in those conversations: the capabilities were exactly right, but getting past the file upload step took more work than it should.

That’s worth fixing properly, not just noting down.

Where the friction was

More than one of those conversations landed on the same step: the file upload. It isn’t a simple POST. Uploads to snapWONDERS go over TUS, the resumable upload protocol I’ve written about before — chunked, resumable, survives a dropped connection. That’s the right choice for a platform where people upload media over patchy connections, including Tor and I2P. It is also, if you’re implementing a client from scratch, genuinely fiddly: create the upload, encode the metadata header correctly, PATCH the chunks in order, handle a resume if a chunk fails. Roughly eighty lines of code that has to be exactly right before you ever see a result.

Nobody integrating a client should have to hand-write that eighty lines. So I built that part for them.

One call instead of eighty lines

The SDKs wrap the whole choreography — create a session, upload each file, start the job, poll until it finishes, download the results — behind one call:

from snapwonders import Client

client = Client(api_key="sw_your_key")

job = client.stego.hide(files=["secret.pdf", "cover.jpg"], password="Str0ng!Pass")
for result in job.results():
    result.download(f"out/{result.name}")

There’s no business logic in the client. Every decision still happens on the server — the SDK’s entire job is making the correct-but-tedious part invisible.

Diagram showing LHS / RHS of busy/complex calls verses a single function call to a SDK

Four languages, written the honest way

About ten percent of an API client can’t be generated from an OpenAPI spec — the TUS upload logic and the session-to-job choreography are exactly that ten percent, and exactly the part developers were flagging. So Python came first, hand-written, as the reference implementation. JavaScript/TypeScript followed the same way, ported by hand rather than generated, because getting the resumable-upload logic right the second time is still worth doing properly rather than mechanically. PHP and Go came after, generated from the live OpenAPI spec with the TUS helper ported across — the pattern was proven twice by then, so the long tail is genuinely cheap.

All four are open source and MIT-licensed:

Language Package Install Source
Python (3.10+) snapwonders pip install snapwonders GitHub
JavaScript / TypeScript (Node 18+) @snapwonders/sdk npm install @snapwonders/sdk GitHub
PHP (8.2+) snapwonders/sdk composer require snapwonders/sdk GitHub
Go (1.21+) go get github.com/snapWONDERS/snapWONDERS-SDK-Go GitHub

Full quickstarts, side-by-side examples for every language, and the interactive API reference live on the developers hub.

The rest of the OpenAPI-generatable languages — Ruby, Java, C#, Rust, and so on — are a short step away: point openapi-generator at the published spec and you have a typed client in minutes. Since this was written the API has gained a direct single-POST upload for files under 95 MB (see the update at the end), so a generated client can now drive the whole flow with no hand-written upload code — hand-porting TUS only comes back if you need it for larger files. Want a language added to the official set, hit an integration snag, or just have a question? Get in touch — that’s also where to report a bug in any of the four.

What I found testing it against the real API

Writing the client against documentation is one thing; running it against production is what actually finds the bugs. It found three. A failed job’s real reason lived in a field the SDK wasn’t reading. A directory download wrote a file literally named out instead of writing into the out/ directory, because a trailing slash on a path that doesn’t exist yet is easy to mishandle. And a maintenance window returned a response shape the SDK’s error handling didn’t recognise, so it retried into a five-minute outage instead of backing off. All three are the same lesson: build against the interface you assume exists, then go and check it against the one that actually responds.

Why this matters more than it looks like it should

The easier an API is to call, the more of it developers actually use. The forensic analysis, the conversion pipeline, the steganography — none of it is more useful to a developer than the least convenient step required to reach it. Fixing the upload wall doesn’t change what the platform does. It changes how much of it developers can put to work without fighting the plumbing first.


Update, 16 August 2026: I removed the wall instead

Five days after publishing this, I did the more obvious thing. The API now also accepts a direct upload — one POST with the file as the body, no chunking, for files up to 95 MB. TUS is still there and still what handles anything larger, and it’s still the right protocol for a 400 MB video over Tor. But it is no longer the only door.

Which slightly undercuts the story above, and I’d rather say so than quietly leave it. The eighty lines were real, and an SDK that hides them is still worth having. But the honest reading is that I spent a fortnight making a hard step easy in four languages before asking whether the step needed to be hard at all. The answer was no — for small files it never did.

What pushed it was a different question: what happens when the thing calling your API is an AI agent rather than a developer? A developer will read the TUS spec and grumble. An agent hits the chunk sequence, gets it subtly wrong, and can’t tell the difference between its own mistake and a service refusing the file. That’s not a documentation problem. So alongside direct upload there’s now a local MCP server that lets an assistant analyse, hide, reveal and convert files on your own machine — which only became a sane thing to build once uploading was a single request.

The lesson generalises further than I’d like: I built the abstraction before questioning the constraint. Worth remembering next time something is annoying enough to wrap.


Kenneth Springer is the founder of snapWONDERS, a digital forensic analysis platform for images and video. This SDK work grew out of building snapWONDERS’ own developer API, which now ships official Python, JavaScript, PHP and Go clients so other developers can call the same forensic analysis, steganography and conversion tools programmatically. snapWONDERS forensic analysis — no account required.

Leave a Reply

Your email address will not be published. Required fields are marked *