One spec in. Ten client libraries that keep up
Idiomatic SDKs in TypeScript, Python, Go, Java, Kotlin, Ruby, PHP, Rust, Swift and Dart, shaped without writing a generator and published to the registries your users already install from. Every one of them reports its own errors back from production.
What your users install
Ten client libraries
A typed client with your auth wired in, retries, pagination and streaming, generated for every language you ship.
What shipsShaped the way you want it
Down to one method
Name the methods, group them, keep the internal endpoints out, and watch the generated code change as you decide.
What you controlOut to the registries
npm, PyPI, Maven
Each release carries the version from your spec, lands where your users already look, and rebuilds when the spec changes.
How it shipsEvery client ships with the parts that take the longest
What comes out is a library someone would be glad to inherit. Typed all the way through, with one place where the HTTP happens and the behaviour your API expects of a good client already in it.
- Typed models and typed errors, so a field that moved fails at compile time, where someone will see it
- One request layer everything goes through, with the status, the request id and how long it took on the way back
- Your auth wired in, read from the security schemes your spec already declares
- Doc comments on every method and model, so your users read your documentation inside their editor
- A test suite generated with it, derived from your schemas, and yours to leave out
- The same surface in all ten, so the method a Go user calls is the method a Python user calls
Retries and timeouts
How many attempts, how long to wait between them, and which statuses are worth trying again. Set for the whole client, or for the one method that needs longer.
Idempotency keys
Writes carry a generated key, so a request the client retried is applied once. Which methods send one, and under which header, is yours.
Pagination
Cursor, offset or page, with an iterator that walks every page so the caller never has to write the loop.
Streaming
Server-sent events and chunked responses come back as typed events a caller can loop over.
And a command line
The same spec also makes a runnable CLI
One switch, and the generated package ships a command-line client beside the library. Every operation you included becomes a subcommand with its parameters as flags.
- A subcommand per endpoint, named the way the method is
- Your auth, read the way a terminal expects it
- Distributed with the package, so there is nothing extra to release
- Off unless you want it, and the library is untouched either way
Ten languages, each one idiomatic to itself
A language is more than a syntax to emit. Each generator ships the transport, the model style, the argument shape and the naming that language's own libraries use, so what your users install looks like the packages they already depend on.
TypeScript
Autodeploys vianpmfetch out of the box, so the client pulls in no HTTP dependency at all.
Python
Autodeploys viaPyPIpydantic response models by default, plain dataclasses when you would rather.
Go
Autodeploys viaa git tagnet/http, and the generated banner Go tooling expects on generated files.
Java
Autodeploys viaMaven Centraljava.net.http, with a builder for the operations wide enough to need one.
Kotlin
Autodeploys viaMaven CentralOkHttp for the JVM and Android, Ktor when you are going multiplatform.
Ruby
Autodeploys viaRubyGemsnet/http, and method names that read the way a Ruby developer expects.
PHP
Autodeploys viaPackagistcURL underneath, installed with Composer like everything else.
Rust
Autodeploys viacrates.ioureq, with typed results a caller can match on.
Swift
Autodeploys viaa git tagURLSession, and labelled arguments at the call site.
Dart
Autodeploys viapub.devthe http client, which is the one a Flutter app already has.
Go modules and Swift packages resolve straight from a repository, so those two have no registry account to connect. Octri publishes them by pushing a tagged commit. For the other eight, connecting the account once is the only setup there is. SDK guides in the docs →
Every choice a generator makes, you make first
SDK Studio is where the client is shaped before a file of it exists. Change something and the code beside it changes with it, so what you are reading is the SDK your users will read.
- The shape of the client: free functions or a client object, and whether operations are grouped by tag or by path
- How methods are named, so an operation your spec calls one thing can be called what your users would call it
- How the source is laid out, one file or a folder per resource
- The base URL and the package name compiled into what you publish, so nobody installs a client pointed at staging
- A live preview in the language you are editing, updating as you go
Precedence
Decide it once. Then decide it again where it matters.
Most settings exist at three levels, and the narrowest one wins. An endpoint override beats a language override, and a language override beats the project default.
- Project: the shape every language starts from
- Language: its package name, its repository, its transport
- Endpoint: the one operation that does not behave like the rest
Your spec has one name for it. Your users get yours
Every operation in the spec is a row you can open. What it is called, what its documentation says, how it behaves, and whether it goes out at all are decided here.
- Rename the method without touching the spec, so tidying an operationId later cannot rename something your users have already called a thousand times
- Write the doc comment that shows up in their autocomplete
- Keep an internal endpoint out entirely, because anything that ships is public API however your documentation describes it
- Deprecate one with a message pointing at what replaced it, so callers get a warning at compile time and their code keeps working while they move
- Say how this one paginates or streams, naming the field the items come back in and the one that advances the page
- Give it its own retry and idempotency rules when the project-wide ones are wrong for it
- Arrange them into folders of your own, or adopt the grouping your documentation sidebar already has
Write into the client, and keep it through the next build
A hook is code you write that the generator compiles into a typed seam around the request. It exists for the things a spec cannot express, like signing a payload on its way out or unwrapping an envelope the API is not ready to drop.
- A seam before the request, taking the parameters, query, body and headers, and returning what actually goes out
- A seam after the response, returning what the caller receives
- Written per language, because a Go client cannot run TypeScript
- Packages your hook imports are declared once and written into the generated manifest, so the dependency is there when your users install
- Edited in the browser or kept in a repository, whichever way your team works
Or own the whole thing
The generated source can live in your repository
Push each language into a repository you control, and every regeneration after that arrives the way any other change to your codebase does.
- A repository per language, which is how SDKs are usually kept anyway
- Regenerations land as a pull request, with a diff you read before it becomes your code
- Your own checks run on it, and their result is visible from the studio
- Nothing reaches your production repository until you promote it
Improve the spec for the SDK without editing the spec
Rewrites applied to the document on its way into the generator. Rename a model, retire a value, or set the thing a control does not cover, all without a pull request against the file your API serves.
- Rewrites that live with the project, applied on every build and never on the original
- Each one carries the reason it exists, so the person who finds it in a year knows what it was for
- A score on your spec, with the operations that will generate badly named one at a time
- Apply a suggested fix and it goes in for you, or dismiss it and it stops asking
- The same audit read twice, once for what hurts the generated client here and once for what hurts the reference page in API Studio
Ten languages build as ten builds
Every language is generated on its own, so the ones that are fine are never waiting on the one that is not. You watch them go, and what comes out is kept.
A failure stays where it is
A language that cannot build is reported with the output that stopped it. The rest of the build ships, and you retry that one on its own.
You can see it working
Each language reports the phase it has reached while the build runs, so a long one shows you where it has got to.
Every build is kept
What shipped, in which languages, at which version, with the files that came out of it, ready to download.
Rebuild without republishing
Regenerate from the last published configuration when you want the artifact fresh and nothing about the config has changed.
Where your users already look: npm install
Connect an account once per language and a release goes out to the registry that language uses. Nobody has to be told where to find your client, because it is where they would have looked first.
- npm, PyPI, Maven Central, crates.io, RubyGems, Packagist and pub.dev, connected once and reused for every release
- Go and Swift published by tag, pushed to the repository they resolve from
- A package name per language, since the conventions differ everywhere you publish
- The README you write is the registry page, and it stays in step with the one in your repository
- Repository metadata in the manifest, so the registry page links back to your source
- Releases pushed for you, and artifacts served from a CDN, from Business. Below that you take the build down as a zip and release it yourself
One version, in every package you ship
A build records the spec that produced it, and publishing carries that version into every manifest. There is no second number to keep in step, and nothing to remember to bump twice.
- One version, set where it belongs. Change it in the spec and the manifests follow on the next build
- A changelog written from what actually changed, entry by entry, and yours to edit before it goes out
- The publish screen shows what is about to happen: which languages will rebuild, and where each is going
- Deprecate for a release or two, then remove, so an operation leaving is a warning first
Merge the spec change. The clients follow
Connect the repository your OpenAPI document lives in, and a merged pull request is all it takes. The API you shipped and the libraries people call it with stop being two things you maintain.
- One merged PR rebuilds the clients, the pages and the changelog together, in under 90 seconds
- Available on every tier, Free included
- Builds start by hand, from a spec change, or from a push, and the history records which
- An endpoint you added is a method your users have the next time they update
Configure it once. Four surfaces change
What you set here is not only what generates. Your documentation, the tools you hand to agents, and the telemetry coming back from production are all reading the same configuration.
Snippets on every page
Your reference pages show the call in your own SDK, using the method name you chose and the client shape you picked.
Behaviour, documented
Retries, pagination and idempotency show up on the endpoint page as things a reader can rely on, without anybody writing them down.
Tools for agents
Every endpoint you included becomes a tool on your MCP server, named and described the way you named and described it here.
Telemetry from the wild
Switch monitoring on and the client reports what it hits in production, from wherever your users installed it.
Bring the configuration you already wrote
Years of decisions go into an SDK config, and they are the part nobody wants to make again. Point Octri at the one you have and it reads it: the spec, the languages, the package naming, and the per-endpoint choices buried in your vendor extensions.
- Speakeasy, Stainless, Fern, liblab and Mintlify configs read directly
- Method renames and pagination markers survive, lifted out of the extensions you set on each operation
- A preview before anything exists, listing what came across and what needs your attention
- Nothing is published until you say so, so the packages your users depend on today keep coming from wherever they come from now
We are also happy to do the move with you while the product is in beta. Comparisons on the blog →
And the parts you only notice when they are missing
Shaping
- Argument style per language, since a params object is not idiomatic everywhere
- Enums that survive a value you have not shipped yet
- Generated tests, or a package without them
- Doc comments in full, or a leaner tree
Getting it out
- Download the build as a zipevery tier, including Free
- Rebuild from the last published config without publishing again
- Retry one language on its own
- Artifacts served from a CDNBusiness and above
Working in it
- Search a thousand operations by path or by name
- Apply one setting to every language at once
- Adopt the grouping your documentation sidebar already uses
- A draft nobody sees until you publish it
One pipeline, from your spec to their import statement
One document and one configuration produce all four: the library your users install, the page that documents it, the tools an agent calls it with, and the monitoring that reports what production hits. Rename a method or add an endpoint and every one of them follows, because none is maintained separately.
Questions
One on Free, two on Starter, four on Growth, and all ten on Business. On Starter and Growth an extra language is $50/mo. Adding one takes effect straight away; dropping one applies at the end of the billing period.