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.

JSON or YAML

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.

The scoreHow it is read

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.

  1. 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.
  2. Shared models live in components and are $ref'd

    up to 2 pointsshared-schemas-referenced
    What it checks
    The same inline object shape, three properties or more, appearing in more than one operation.
    What it costs you
    Inline object schemas become anonymous per-operation types. The same model inlined in 20 operations generates 20 near-identical types instead of one.
    What to do
    Move the shape into components.schemas once and $ref it from each operation that returns or accepts it.
  3. 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.
  4. 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.
  5. 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.
  6. 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.
  7. 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.
  8. 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.
  9. 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.
  10. 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()`.
  11. 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.
  12. 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.
  13. 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.
  14. 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.

Public scoresScored by us

Specs you have heard of, scored

Public OpenAPI documents we fetched and scored against the same fourteen rules. Each one has its own page.

SpecScoreOperationsLast scored
Adyen Checkout APIraw.githubusercontent.com8.7Strong2814 Sept 2026
Twilio SendGrid Mail APIraw.githubusercontent.com8.6Strong314 Sept 2026
Box Platform APIraw.githubusercontent.com8.4Strong29714 Sept 2026
Slack Web APIraw.githubusercontent.com8.3Strong17414 Sept 2026
Swagger Petstore - OpenAPI 3.0petstore3.swagger.io8.3Strong1914 Sept 2026
Asanaraw.githubusercontent.com8.2Strong24914 Sept 2026
OpenAI APIraw.githubusercontent.com8.0Strong33814 Sept 2026
The Plaid APIraw.githubusercontent.com7.8Mixed35114 Sept 2026
Twilio - Apiraw.githubusercontent.com7.3Mixed19714 Sept 2026
GitHub v3 REST APIraw.githubusercontent.com6.8Mixed122914 Sept 2026
Stripe APIraw.githubusercontent.com6.6Mixed59414 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.