An API quality checklist for a design review should cover seven things: path naming, HTTP method use, path depth, consistency across paths, versioning, documented error responses, and operation summaries. Those are the seven categories APIForge's deterministic score checks, worth 20, 20, 15, 15, 10, 10 and 10 points. This page turns each category into review questions, shows the exact rule behind each deduction, and scores one small spec before and after fixes so you can see where the points go.
Design review versus release readiness
This checklist is for the design review, when a pull request adds or renames endpoints and someone has to decide whether the shape is right. It looks at the surface a client developer sees first: URLs, methods, status codes and descriptions. It does not ask whether the document is valid OpenAPI, whether every $ref resolves, or whether security schemes are declared. Those belong to the release gate, and the OpenAPI production checklist covers them. Run both, at different moments: design review on every endpoint change, the release gate before you publish a spec or generate SDKs.
The seven categories and their weights
| Category | Max points | What costs points |
|---|---|---|
| Naming | 20 | camelCase anywhere in the path, underscores in a static segment, a segment that is exactly a verb |
| HTTP | 20 | A GET with a request body, an action word such as /create or /get- after a slash |
| Structure | 15 | Paths with more than 3 segments, counting the version prefix and parameters |
| Consistency | 15 | Duplicate method and path pairs, singular and plural forms of the same noun |
| Versioning | 10 | No path segment like v1 or v2 anywhere in the spec |
| Error handling | 10 | Operations with no 4xx, 5xx or default response |
| Documentation | 10 | Operations with neither a summary nor a description |
Most categories are averaged per operation. Each operation starts at 1, loses a fraction for each problem, and the category score is the average multiplied by the category maximum. One bad endpoint in a spec of twenty costs little; the same mistake copied across every endpoint costs the whole category. Consistency and versioning are judged across the whole spec instead.
The checklist, category by category
Naming (20 points)
- Are multi-word segments kebab-case, such as /line-items? A camelCase match costs the operation 0.45 of its naming share.
- Are static segments free of underscores? /line_items costs 0.35.
- Is no segment a bare verb? The rule matches whole segments against get, post, put, patch, delete, create, update, remove, fetch, list, add, edit and save. /orders/create costs 0.55.
- Are path parameter names plain? The camelCase rule reads the whole path string, so {orderId} counts as camelCase and so does {order_id}. Either accept the deduction or use {id}.
The whole-segment match has a blind spot. /createOrder is one segment, so the verb rule does not fire; the camelCase rule catches it instead. The API naming conventions guide covers the wider naming decisions the score cannot judge, such as whether a collection name is the right noun.
HTTP method use (20 points)
- Does any GET operation declare a requestBody? That costs the operation its full HTTP share. RFC 9110 says content in a GET request has no generally defined semantics, and some intermediaries reject it.
- Does a path put an action after a slash? The check matches create, update, delete, remove, get, fetch, add and save followed by a word boundary, so /get-users loses 0.45 even though the naming rule does not see a bare verb there.
- For complex queries that need a body, model the search as its own resource and POST to it, such as POST /v1/order-searches.
In a probe spec, GET /v1/get-users dropped the HTTP category without adding a line to the issue list, because the issue list only names create, update, delete and remove in its action-word message. If the HTTP score is below 20 and the issues do not explain it, look for get, fetch, add or save at the start of a segment.
Structure (15 points)
Count every segment, including the version prefix and path parameters. /v1/orders/{id} is 3 segments and costs nothing. Each segment past 3 costs 0.22 of the operation's share, capped at 0.9, and the issue list adds a message once a path passes 4 segments. Adding /v1 to an API therefore spends one segment of the budget, so /v1/orders/{id}/items starts losing points. When a child resource has its own stable ID, give it a top-level path such as /v1/line-items/{id}.
Consistency (15 points)
- Does any method and path pair appear twice? Each duplicate costs 0.45 of the category.
- Does the spec use both order and orders as segments? Mixing singular and plural forms of one noun costs 0.5. The check strips a trailing s, so it catches order and orders but not person and people.
- Penalties add up and the category floors at zero.
Versioning (10 points)
The score gives the full 10 points if any path contains a segment like v1, and 1 point otherwise. Header or media-type versioning earns nothing here, even though the fix text mentions version headers. If your team versions by header on purpose, record that decision in the review and treat this category as known. The API versioning guide compares the strategies.
Error handling (10 points)
This is the share of operations that declare at least one 4xx, 5xx or default response. It counts presence only. A bare "404" with a one-word description earns the same as a full problem details schema, and a 429 or 401 is never asked for. Use the score to find operations with no error responses at all, then review the error body by hand against the REST API error handling guide. An operation that also lacks any 2xx response is flagged under error handling as well.
Documentation (10 points)
This is the share of operations with a non-empty summary or description. A summary like "Get one order" is enough for the points. Whether the text helps a reader is a review question the score cannot answer, so read the summaries out loud during the review and rewrite any that repeat the path.
Worked example: an Orders API scored before and after
Here is a five-operation spec with the kind of problems that slip through reviews: a verb-shaped path, a GET with a body, a singular path next to a plural one, a deep nested delete, missing summaries, and no version prefix.
openapi: 3.0.3
info:
title: Orders API
version: 1.0.0
paths:
/orders:
get:
summary: List orders
responses:
"200":
description: A page of orders
/createOrder:
post:
requestBody:
content:
application/json:
schema:
type: object
responses:
"201":
description: Order created
/order/{orderId}:
get:
summary: Get one order
parameters:
- name: orderId
in: path
required: true
schema:
type: string
responses:
"200":
description: The order
"404":
description: Order not found
/orders/search:
get:
summary: Search orders
requestBody:
content:
application/json:
schema:
type: object
responses:
"200":
description: Matching orders
/customers/{customerId}/orders/{orderId}/line_items/{itemId}:
delete:
parameters:
- name: customerId
in: path
required: true
schema:
type: string
- name: orderId
in: path
required: true
schema:
type: string
- name: itemId
in: path
required: true
schema:
type: string
responses:
"204":
description: Line item removedRunning npm run content:score on this file, which calls the same engine as the APIForge workspace, returned 58.7 out of 100 with 14 issues.
| Category | Before | Main cause |
|---|---|---|
| Naming (20) | 13.2 | /createOrder, plus {orderId} and {customerId} read as camelCase, plus line_items |
| HTTP (20) | 16 | GET /orders/search carries a request body |
| Structure (15) | 13 | The delete path has 6 segments |
| Consistency (15) | 7.5 | order and orders both appear |
| Versioning (10) | 1 | No /v1 segment |
| Error handling (10) | 2 | Only GET /order/{orderId} declares an error response |
| Documentation (10) | 6 | POST /createOrder and the delete have no summary |
The fixes, in the order a reviewer would ask for them
Add the version prefix first
Prefix every path with /v1. This is worth 9 points on its own and changes path depth, so do it before you judge structure.
Turn actions into resources
POST /createOrder becomes POST /v1/orders. The search moves from GET with a body to POST /v1/order-searches, a resource that represents the query.
Pick plural nouns everywhere
/order/{orderId} becomes /v1/orders/{id}, which removes the singular and plural clash and the camelCase parameter.
Flatten the delete
Line items have their own IDs, so the delete becomes DELETE /v1/line-items/{id}: 3 segments, kebab-case, no underscore.
Declare an error response and a summary on every operation
Add 400, 404 or 422 where each one can really happen, and a one-line summary to the two operations that had none.
openapi: 3.0.3
info:
title: Orders API
version: 1.0.0
paths:
/v1/orders:
get:
summary: List orders
parameters:
- name: status
in: query
schema:
type: string
enum: [open, paid, shipped]
responses:
"200":
description: A page of orders
"400":
description: Invalid filter value
post:
summary: Create an order
requestBody:
content:
application/json:
schema:
type: object
responses:
"201":
description: Order created
"422":
description: Order failed validation
/v1/orders/{id}:
get:
summary: Get one order
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
"200":
description: The order
"404":
description: Order not found
/v1/order-searches:
post:
summary: Run a complex order search
requestBody:
content:
application/json:
schema:
type: object
responses:
"200":
description: Matching orders
"400":
description: Malformed search
/v1/line-items/{id}:
delete:
summary: Remove a line item from its order
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
"204":
description: Line item removed
"404":
description: Line item not foundThe fixed spec scores 100 with an empty issue list. When we renamed {id} back to {orderId} on the two single-item paths, naming fell to 16.4 and the total to 96.4, purely because of the parameter name. Plenty of teams prefer {orderId} because it reads well in generated client code. Keeping it is a reasonable call; record it in the review so nobody chases those 3.6 points later.
What a 100 does not tell you
The score reads paths, methods, the presence of a request body, response status codes and summaries. Everything else needs a human or a different tool. Keep these on the review checklist even when the number is perfect:
- Spec validity. The score parses what it can; run the OpenAPI validator for structural errors and unresolved $ref pointers.
- Security. securitySchemes and security requirements are not read at all. A spec with every auth block removed scores the same. See API security best practices.
- Schemas. Request and response schemas are not inspected, so missing required lists, loose types and absent examples pass.
- operationId. The OpenAPI Specification says each operationId must be unique among all operations; the score does not check that.
- Rate limits. A 429 response and RateLimit headers are not required for points. See API rate limiting.
- Error body shape. A declared 404 with no schema earns full credit.
Using the score in a pull request review
Score the spec on the main branch and on the pull request, then compare category by category rather than the total. A total can stay flat while one category drops and another rises, and the drop is what the reviewer needs to see. Set floors per category that match your conventions: if you version by header, accept 1 point in versioning and fail on anything less than 20 in naming. Then spend the human part of the review on the items in the previous section, which is where the score says nothing.
To try it on your own API, paste a spec URL into the APIForge workspace and open the quality score; the API quality score page lists the same seven categories. The score runs in the browser and shows the issue list with a suggested fix for each one.