Score your OpenAPI spec for SDK generation
Octri runs this audit on every spec it generates a client from. Paste a URL and get the same score out of 10, on the same fourteen rules, before anyone builds against your API. No account, and the spec is not kept.
An example audit runs alongside: a readiness score of 6.8 out of 10 across 24 operations, with the rules the spec passed and failed scrolling past it.
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.
Up to 2 points
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.
Up to 2 points
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.
Up to 2 points
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.
Successful responses declare a schema
up to 2 pointsresponse-schema- What it checks
- Every operation with a 2xx response other than 204 or 205 has a schema on that response.
- What it costs you
- Without a response schema every method returns `unknown`/`any`, so callers get no types and no autocompletion.
- What to do
- Give the success response a schema, or a $ref to one in components. A 204 needs nothing.
Generated public names do not collide
up to 2 pointsoperation-id-unique- What it checks
- The public name each operation resolves to, namespace and method together, checked for collisions across the whole document.
- What it costs you
- 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.
- What to do
- 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 parameter
up to 1.5 pointspath-parameters-declared- What it checks
- Each `{placeholder}` in a path template has a matching `in: path` parameter on the operation or the path item.
- What it costs you
- An undeclared `{id}` placeholder cannot become a typed method argument, so the generated request path is incomplete or uncompilable.
- What to do
- Declare the parameter with `in: path`, `required: true`, and a type.
Every operation declares an operationId
up to 1 pointoperation-id-present- What it checks
- Operations with no operationId at all.
- What it costs you
- Without one the generator synthesizes a name from the path, which changes whenever the path does. That is a silent breaking change for callers.
- What to do
- Add an operationId. It pins the generated method name to something you control.
operationIds read as method names
up to 1 pointoperation-id-naming- What it checks
- operationIds that repeat their own namespace or trail the HTTP verb, measured against the name the generator would suggest.
- What it costs you
- The id becomes the method name. `ActionsActionsGet` generates `client.actions.actionsActionsGet()`; `getActions` generates `client.actions.get()`.
- What to do
- Name the id for the action, not the route. The audit suggests one per operation and can apply it.
Operations carry a summary or description
up to 1 pointoperation-documented- What it checks
- Operations with neither a summary nor a description.
- What it costs you
- Operation prose becomes the method's doc comment, the text an IDE shows on hover.
- What to do
- Write one sentence of summary. It lands on the reference page and in the SDK's doc comment.
Request bodies are documented
up to 1 pointrequest-body-documented- What it checks
- Request bodies that have a schema but no description on the body or on its fields.
- What it costs you
- Body field descriptions become the doc comments on generated parameters; without them the SDK ships undocumented arguments.
- What to do
- Describe the body, or the fields inside it. Field-level prose is the one that reaches the SDK's arguments.
Failure responses are declared
up to 1 pointerror-responses- What it checks
- Operations declaring no 4xx, no 5xx and no `default` response.
- What it costs you
- Declared error schemas become typed errors. Without them every failure surfaces as an untyped generic error.
- What to do
- Declare the failures you actually return, or one `default` response carrying your error shape.
Operations are tagged
up to 1 pointoperation-tagged- What it checks
- Operations with an empty or missing `tags` array.
- What it costs you
- Tags drive namespacing. Untagged operations fall back to a path segment, producing lopsided or `misc` namespaces.
- What to do
- Tag every operation. Tags are what decide whether a caller writes `client.invoices.list()` or `client.misc.list()`.
No duplicate or equivalent paths
up to 1 pointduplicate-paths- What it checks
- Paths that are identical once the parameter names are erased, such as `/users/{id}` beside `/users/{userId}`.
- What it costs you
- 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.
- What to do
- Keep one. A server routes both to the same handler, so the second is a duplicate method for your users.
Authentication is described
up to 1 pointsecurity-declared- What it checks
- Whether `components.securitySchemes` declares anything at all.
- What it costs you
- Security schemes generate the SDK's auth configuration. A spec without them produces a client with no way to authenticate.
- What to do
- 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 purpose
up to 0.75 pointsparameters-documented- What it checks
- Query, path, header and cookie parameters with a name and a location but no description.
- What it costs you
- Parameter descriptions become IDE hints on generated method arguments; bare names force SDK users back to the API reference.
- What to do
- Describe what the parameter does and what a valid value looks like. One line each.
A server URL is declared
up to 0.5 pointsserver-url- What it checks
- Whether the document declares at least one entry under `servers`.
- What it costs you
- Without a server URL the generated client must ship with an empty or placeholder base URL, adding setup work and easy production misconfiguration.
- What to do
- 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 | Operations | Last scored |
|---|---|---|---|
| Adyen Checkout APIraw.githubusercontent.com | 8.7Strong | 28 | 14 Sept 2026 |
| Twilio SendGrid Mail APIraw.githubusercontent.com | 8.6Strong | 3 | 14 Sept 2026 |
| Box Platform APIraw.githubusercontent.com | 8.4Strong | 297 | 14 Sept 2026 |
| Slack Web APIraw.githubusercontent.com | 8.3Strong | 174 | 14 Sept 2026 |
| Swagger Petstore - OpenAPI 3.0petstore3.swagger.io | 8.3Strong | 19 | 14 Sept 2026 |
| Asanaraw.githubusercontent.com | 8.2Strong | 249 | 14 Sept 2026 |
| OpenAI APIraw.githubusercontent.com | 8.0Strong | 338 | 14 Sept 2026 |
| The Plaid APIraw.githubusercontent.com | 7.8Mixed | 351 | 14 Sept 2026 |
| Twilio - Apiraw.githubusercontent.com | 7.3Mixed | 197 | 14 Sept 2026 |
| GitHub v3 REST APIraw.githubusercontent.com | 6.8Mixed | 1229 | 14 Sept 2026 |
| Stripe APIraw.githubusercontent.com | 6.6Mixed | 594 | 14 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.
- 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.
- The score is rechecked on every spec change, which is what catches a new endpoint shipped without a response schema.
- The same document generates the reference pages, the SDKs in ten languages and the MCP server, so one fix reaches all of them.
- Findings a docs reader feels are split out from findings only an SDK user feels, and each studio shows its own.
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.