A number about the SDK, not about the API
The audit does not grade your API. It predicts what a code generator will be able to do with the document that describes it.
An API can be well designed, fast and widely used, and still describe itself in a way that produces a miserable client. The two are separate problems. A response with no declared schema is a method that returns any. An operation with no tag lands in a namespace named after a path segment. Two operations that resolve to the same public name, whatever their operationIds say, collide into one method, and the generator has to rename one of them behind your back.
So every rule below states what breaks in generated output rather than what offends a style guide. If a rule cannot name the consequence, it does not carry weight.
Deductions scale with how much of your surface a rule touches. One undocumented operation out of 500 costs almost nothing; a spec that documents none of them loses that rule’s full weight. A rule that fires at all costs a fifth of its weight straight away, because some failures matter at any scale.
8.0 and up
Strong
Generation gives you typed methods, named models and real doc comments. What is left is polish you can do after the first release.
6.0 to 7.9
Mixed
The client compiles and works, with soft spots your users will feel: a few untyped returns, some bare arguments, a namespace or two named after a path segment.
Under 6.0
Weak
Enough of the surface is undeclared that the generated client leaks the spec’s gaps into every caller. Fix the heavyweight rules before you publish an SDK from it.
Where the points actually go
Three rules can take 6 of the 10 between them. When a spec scores badly, it is almost always these.
The 14 rules by weight, heaviest first: 3 carry 2 points each, and the remaining 11 carry between 0.5 and 1.5. Every weight is listed in the table below.
Successful responses declare a schema
Without a response schema every method returns `unknown`/`any`, so callers get no types and no autocompletion.
Fix: Give the success response a schema, or a $ref to one in components. A 204 needs nothing.
Shared models live in components and are $ref'd
Inline object schemas become anonymous per-operation types. The same model inlined in 20 operations generates 20 near-identical types instead of one.
Fix: Move the shape into components.schemas once and $ref it from each operation that returns or accepts it.
Generated public names do not collide
When authored identifiers collapse to the same shared public name, the generator must silently rename one method; callers otherwise cannot predict the SDK surface from the spec.
Fix: Rename the authored operationId, or set that operation's SDK namespace. The audit proposes one and can apply it; your tags and the wire operation are left alone.
The fourteen rules, in full
All fourteen rules, heaviest first, with the weight each one can cost out of 10.
| Rule | Weight | What it checks | What it costs you | What to do |
|---|---|---|---|---|
Successful responses declare a schemaresponse-schema | 2 pts | Every operation with a 2xx response other than 204 or 205 has a schema on that response. | Without a response schema every method returns `unknown`/`any`, so callers get no types and no autocompletion. | Give the success response a schema, or a $ref to one in components. A 204 needs nothing. |
Shared models live in components and are $ref'dshared-schemas-referenced | 2 pts | The same inline object shape, three properties or more, appearing in more than one operation. | Inline object schemas become anonymous per-operation types. The same model inlined in 20 operations generates 20 near-identical types instead of one. | Move the shape into components.schemas once and $ref it from each operation that returns or accepts it. |
Generated public names do not collideoperation-id-unique | 2 pts | The public name each operation resolves to, namespace and method together, checked for collisions across the whole document. | When authored identifiers collapse to the same shared public name, the generator must silently rename one method; callers otherwise cannot predict the SDK surface from the spec. | Rename the authored operationId, or set that operation's SDK namespace. The audit proposes one and can apply it; your tags and the wire operation are left alone. |
Every path placeholder has a parameterpath-parameters-declared | 1.5 pts | Each `{placeholder}` in a path template has a matching `in: path` parameter on the operation or the path item. | An undeclared `{id}` placeholder cannot become a typed method argument, so the generated request path is incomplete or uncompilable. | Declare the parameter with `in: path`, `required: true`, and a type. |
Every operation declares an operationIdoperation-id-present | 1 pt | Operations with no operationId at all. | Without one the generator synthesizes a name from the path, which changes whenever the path does. That is a silent breaking change for callers. | Add an operationId. It pins the generated method name to something you control. |
operationIds read as method namesoperation-id-naming | 1 pt | operationIds that repeat their own namespace or trail the HTTP verb, measured against the name the generator would suggest. | The id becomes the method name. `ActionsActionsGet` generates `client.actions.actionsActionsGet()`; `getActions` generates `client.actions.get()`. | Name the id for the action, not the route. The audit suggests one per operation and can apply it. |
Operations carry a summary or descriptionoperation-documented | 1 pt | Operations with neither a summary nor a description. | Operation prose becomes the method's doc comment, the text an IDE shows on hover. | Write one sentence of summary. It lands on the reference page and in the SDK's doc comment. |
Request bodies are documentedrequest-body-documented | 1 pt | Request bodies that have a schema but no description on the body or on its fields. | Body field descriptions become the doc comments on generated parameters; without them the SDK ships undocumented arguments. | Describe the body, or the fields inside it. Field-level prose is the one that reaches the SDK's arguments. |
Failure responses are declarederror-responses | 1 pt | Operations declaring no 4xx, no 5xx and no `default` response. | Declared error schemas become typed errors. Without them every failure surfaces as an untyped generic error. | Declare the failures you actually return, or one `default` response carrying your error shape. |
Operations are taggedoperation-tagged | 1 pt | Operations with an empty or missing `tags` array. | Tags drive namespacing. Untagged operations fall back to a path segment, producing lopsided or `misc` namespaces. | Tag every operation. Tags are what decide whether a caller writes `client.invoices.list()` or `client.misc.list()`. |
No duplicate or equivalent pathsduplicate-paths | 1 pt | Paths that are identical once the parameter names are erased, such as `/users/{id}` beside `/users/{userId}`. | Paths differing only in parameter NAME are the same route to a server; the generated SDK ends up with two methods that call the same endpoint. | Keep one. A server routes both to the same handler, so the second is a duplicate method for your users. |
Authentication is describedsecurity-declared | 1 pt | Whether `components.securitySchemes` declares anything at all. | Security schemes generate the SDK's auth configuration. A spec without them produces a client with no way to authenticate. | Declare the scheme you use, such as an http bearer or an apiKey header, and reference it from the operations it guards. |
Parameters explain their purposeparameters-documented | 0.75 pts | Query, path, header and cookie parameters with a name and a location but no description. | Parameter descriptions become IDE hints on generated method arguments; bare names force SDK users back to the API reference. | Describe what the parameter does and what a valid value looks like. One line each. |
A server URL is declaredserver-url | 0.5 pts | Whether the document declares at least one entry under `servers`. | Without a server URL the generated client must ship with an empty or placeholder base URL, adding setup work and easy production misconfiguration. | Add your production base URL under `servers`. Add the others too if you publish a sandbox. |
One more finding sits outside the score. A spec past roughly 300 operations or 400 models gets packaging advice rather than a deduction, because the fix is structural: split the client by tag so a caller who uses three endpoints does not install all three hundred.
Specs you have heard of, scored
Public OpenAPI documents we fetched and scored against the same fourteen rules. Each one has its own page.
| Spec | Score | Reading | Operations | Last scored |
|---|---|---|---|---|
| Box Platform APIraw.githubusercontent.com | 8.7 | Strong | 297 | 17 Oct 2026 |
| Adyen Checkout APIraw.githubusercontent.com | 8.7 | Strong | 28 | 2 Oct 2026 |
| Twilio SendGrid Mail APIraw.githubusercontent.com | 8.6 | Strong | 3 | 14 Sept 2026 |
| Swagger Petstore - OpenAPI 3.0petstore3.swagger.io | 8.3 | Strong | 19 | 8 Oct 2026 |
| Slack Web APIraw.githubusercontent.com | 8.3 | Strong | 174 | 14 Sept 2026 |
| Asanaraw.githubusercontent.com | 8.2 | Strong | 251 | 15 Oct 2026 |
| The Plaid APIraw.githubusercontent.com | 7.8 | Mixed | 350 | 16 Oct 2026 |
| OpenAI APIraw.githubusercontent.com | 7.6 | Mixed | 360 | 17 Oct 2026 |
| Twilio - Apiraw.githubusercontent.com | 7.3 | Mixed | 197 | 7 Oct 2026 |
| GitHub v3 REST APIraw.githubusercontent.com | 6.9 | Mixed | 1242 | 17 Oct 2026 |
| Stripe APIraw.githubusercontent.com | 6.6 | Mixed | 612 | 30 Sept 2026 |
Each report is a reading of the document, not a grade of the API, and none of these vendors is affiliated with Octri. Scores are re-taken when the spec changes. To add your own, tick the publish box when you run the audit above.
What happens to a spec after it scores
The audit is the first thing Octri runs on a spec, and it keeps running.
Fix it in place
9 of the fourteen rules carry a button that writes the change into your spec and rescores it, so the number moves when you act on it.
Rechecked on every change
The score is re-taken whenever the document moves, which is what catches a new endpoint shipped without a response schema.
One fix, every surface
The same document generates the reference pages, the SDKs in ten languages and the MCP server, so one change reaches all of them.
Split by who feels it
Findings a docs reader feels are separated from findings only an SDK user feels, and each studio shows its own.
Where to go next
- Generate a TypeScript SDK from OpenAPI Published to npm, with the type definitions generated from your spec.
- Generate a Python SDK from OpenAPI Published to PyPI. Async first, with optional sync variants.
- Generate an MCP server from OpenAPI The same endpoints, as tools an agent can call.
- How SDK Studio shapes a client Namespaces, method names and auth, settled before anything ships.
Questions
No. We keep the `info` block your spec declares, which is its title, version and contact, plus which rules deducted points. The document itself is read, scored and dropped. A URL you paste to a private staging spec does not become a copy on our side.