IPA-117: Documentation
Documentation serves as a primary tool for clients to better understand an API and its functionality. Consistent documentation patterns across the API platform will promote clarity, completeness and consistency.
Guidance
Descriptions
API producers must provide descriptions for properties, operations, parameters, and tags.
paths:
/orders/{orderId}:
get:
summary: Return One Order
description: Returns a single order by its unique identifier.
parameters:
- name: orderId
in: path
description: Unique identifier of the order to return.
schema:
type: stringWhy:The operation, the parameter, and (elsewhere) every property each carry a description, so a consumer reading the generated reference learns what each element is without inspecting the implementation.
paths:
/orders/{orderId}:
get:
summary: Return One Order
parameters:
- name: orderId
in: path
schema:
type: stringWhy:Neither the operation nor the parameter has a description, leaving a consumer to guess what the endpoint does and what
orderIdmeans.API producers may provide descriptions for schemas.
Descriptions should be complete but brief. A good description aims to cover what the element is, how to use it, default values, optional or required behavior, and common errors.
properties:
status:
type: string
description: >-
Current state of the order. Defaults to PENDING when an order is created.
Transitions to SHIPPED once fulfillment begins and to CANCELED if the
order is withdrawn before shipping.
enum: [PENDING, SHIPPED, CANCELED]
default: PENDINGWhy:The description names the field, its default, and the meaning of each state in a few sentences, so a consumer needs nothing else to use it correctly.
properties:
status:
type: string
description: The status.
enum: [PENDING, SHIPPED, CANCELED]
default: PENDINGWhy:The description restates the field name and omits the default and the meaning of each state, so it is brief but not complete.
Collect every
descriptionon properties, operations, parameters, and tags.For each description, check that it covers the applicable facets: what the element is, how to use it, default value, whether it is optional or required, and common errors. Not every facet applies to every element.
Confirm the description stays brief: a few sentences, no padding that merely restates the field name or type.
Report descriptions that are empty of substance, that restate the name, or that omit an applicable facet such as a default value.
Descriptions should avoid overly technical language and should prefer simple syntax that can easily be translated for non-English speakers.
properties:
retryCount:
type: integer
description: Number of times the job was retried after a failure.Why:Plain wording and a simple sentence convey the meaning to a non-specialist and translate cleanly.
properties:
retryCount:
type: integer
description: >-
Cardinality of idempotent re-invocations dispatched by the orchestrator
subsequent to a non-terminal fault condition.Why:Jargon and a dense clause obscure a simple idea and resist translation.
- Collect every
descriptionacross the spec. Flag descriptions that rely on jargon, acronyms, or nested clauses where a plain sentence would convey the same meaning.
Report descriptions that a non-native English reader, or a translation tool, would struggle to parse.
- Collect every
Descriptions must avoid company internal language conventions.
properties:
ownerId:
type: string
description: Unique identifier of the user who owns this project.Why:The wording uses terms a public consumer understands rather than an internal codename or team-specific shorthand.
properties:
ownerId:
type: string
description: The principal ref from the legacy AuthZ blob, see PROJ-204.Why:Internal codenames, ticket numbers, and team jargon are meaningless to an external consumer and leak implementation context.
- Collect every
descriptionacross the spec. Flag descriptions containing internal codenames, ticket references, team names, or shorthand that only an employee would recognize.
- Report each such description as a violation.
- Collect every
Descriptions should describe fields in terms meaningful to API consumers, not in terms of API mechanics. Referencing other API-specific constructs couples the description to tooling context that is not visible to end users of generated clients and forces downstream tooling to override the text.
properties:
organizationId:
type: string
description: >-
Unique 24-hexadecimal digit string that identifies the organization that
contains the projects.Why:The description explains the field on its own terms, so it reads the same in a generated SDK as in the raw spec.
properties:
organizationId:
type: string
description: >-
Unique 24-hexadecimal digit string that identifies the organization. Use
the listOrganizations operation on the /orgs endpoint to retrieve all
organizations to which the authenticated user has access.Why:Naming an operationId and endpoint path ties the text to API mechanics that a consumer of a generated client never sees, forcing tooling to rewrite the description.
Collect every property
descriptionacross the spec.Flag descriptions that reference operationIds, endpoint paths, or other spec-internal constructs instead of explaining the field in consumer terms.
Report each such description so the API mechanics can be removed or moved to external documentation.
When the same property appears in multiple polymorphic variants unified by
oneOfwith a discriminator (see IPA-125), that property's description should be identical across variants. Variant-specific context should be documented in the variant schema's owndescription, not by diverging the property's description between variants.components:
schemas:
CardPayment:
type: object
properties:
amount:
type: integer
description: Total charged, in the smallest currency unit.
BankPayment:
type: object
properties:
amount:
type: integer
description: Total charged, in the smallest currency unit.Why:The shared
amountproperty reads identically in every variant, so a consumer sees one consistent definition regardless of which variant is returned.components:
schemas:
CardPayment:
type: object
properties:
amount:
type: integer
description: Total charged to the card, in the smallest currency unit.
BankPayment:
type: object
properties:
amount:
type: integer
description: Amount of the transfer in cents after fees are deducted.Why:The same property carries diverging descriptions across variants, so the generated docs show conflicting definitions for one field; the card-specific note belongs on the variant schema, not on
amount.Find every
oneOfwith a discriminator and collect the variant schemas it unifies.Across those variants, group properties that share a name.
For each shared property, compare its
descriptionacross variants and flag any divergence.Report shared properties whose descriptions differ, and check that any variant-specific note lives on the variant schema's own
description.
Depends on
See Description Object.
Documentation may link to external documentation, using the
externalDocsobject, when more in-depth information is pertinent. See External Documentation Object.
Description Formatting
Descriptions may use CommonMark.
Descriptions must start with an uppercase letter.
parameters:
- name: status
in: query
description: Filter results by order status.
schema:
type: stringWhy:The description begins with a capital letter, matching prose conventions across the reference.
parameters:
- name: status
in: query
description: filter results by order status.
schema:
type: stringWhy:A lowercase opening reads as an unfinished fragment and breaks the consistent sentence style of the reference.
Descriptions must end with a full stop (
.).parameters:
- name: status
in: query
description: Filter results by order status.
schema:
type: stringWhy:The terminating period marks the description as a complete sentence.
parameters:
- name: status
in: query
description: Filter results by order status
schema:
type: stringWhy:Without a final period the description reads as a truncated fragment and diverges from the rest of the reference.
Descriptions must not use raw HTML.
properties:
notes:
type: string
description: |
Free-form notes about the order. Supports the following:
- shipping instructions
- gift messagesWhy:CommonMark renders consistently across the tools that consume the spec, including generated client documentation.
properties:
notes:
type: string
description: >-
Free-form notes about the order. Supports <ul><li>shipping
instructions</li><li>gift messages</li></ul>.Why:Raw HTML tags are not rendered uniformly by spec tooling and often surface as literal text in generated clients.
Descriptions should not include inline tables, as these may not work well with all tools and in particular generated client code. Consider using lists over tables; if a comprehensive description with tables is needed, prefer a short description plus
externalDocs.properties:
tier:
type: string
description: |
Service tier for the account. Available tiers:
- FREE: no monthly cost, limited quota
- PRO: monthly cost, expanded quotaWhy:A short list conveys the same information as a table and renders reliably in generated client documentation.
properties:
tier:
type: string
description: |
Service tier for the account.
| Tier | Cost | Quota |
| ---- | ------- | -------- |
| FREE | none | limited |
| PRO | monthly | expanded |Why:Inline tables are rendered inconsistently across tools and frequently collapse into unreadable text in generated clients.
Descriptions should not include inline links. When links to external documentation are needed, use the
externalDocsobject instead.properties:
region:
type: string
description: Geographic region where the resource is hosted.
externalDocs:
description: Supported regions
url: https://example.com/docs/regionsWhy:Moving the link to
externalDocskeeps the description plain text that every tool can render and translate.properties:
region:
type: string
description: >-
Geographic region where the resource is hosted. See [supported
regions](https://example.com/docs/regions).Why:An inline link embeds markup that some tools strip or mangle in generated clients; the structured
externalDocsobject survives the round trip.
Sensitive Field Markings
The OpenAPI format: password keyword identifies properties whose value is
itself a secret. Guidelines below govern when to apply it.
Must use
format: passwordon any property whose value is itself a secret per IPA-111 — Sensitive Fields.components:
schemas:
ApiKey:
type: object
properties:
key:
type: string
format: password
writeOnly: trueWhy:The
keyproperty carries a secret value (an API key), soformat: passwordmarks it as a secret for tooling and consumers.components:
schemas:
ApiKey:
type: object
properties:
key:
type: string
writeOnly: trueWhy:The
keyis write-only but lacksformat: password, so tooling cannot distinguish it from any other write-only string field.Identify all properties that carry a secret value per IPA-111.
Confirm each such property sets
format: passwordin its schema.Report secret-carrying properties that omit
format: password.
Depends onMust not use
format: passwordon a redacted sibling property whose value is a masked display (****, last-4 digits, etc.). The redacted value is not itself a secret; marking it as such misleads consumers and tooling.components:
schemas:
ApiKey:
type: object
properties:
key:
type: string
format: password
writeOnly: true
keyRedacted:
type: string
description: Last four characters of the API key.
readOnly: trueWhy:Only the raw
keycarriesformat: password. The redacted siblingkeyRedactedcarries a masked display, not a secret, so it omits the format.components:
schemas:
ApiKey:
type: object
properties:
key:
type: string
format: password
writeOnly: true
keyRedacted:
type: string
format: password
description: Last four characters of the API key.
readOnly: trueWhy:keyRedactedis a masked display whose value is not a secret — it repeats a few characters the consumer already provided. Marking it withformat: passwordmisleads tooling into treating the redacted value as a secret.Identify redacted sibling properties — read-only fields that show a masked or truncated display of a sensitive field.
Confirm none of these sibling properties carries
format: password.Report redacted siblings that are incorrectly marked with
format: password.
Depends on
Examples
API producers must provide a well-defined schema or example(s) for objects, request and response bodies, and parameters. Tools can leverage schemas and field examples to generate request and response examples.
paths:
/orders:
post:
summary: Create One Order
requestBody:
content:
application/json:
schema:
$ref: "#/components/schemas/Order"
responses:
"201":
description: Order created.
content:
application/json:
schema:
$ref: "#/components/schemas/Order"Why:Both the request and response bodies reference a defined schema, so tooling can generate accurate examples and consumers know the exact shape.
paths:
/orders:
post:
summary: Create One Order
requestBody:
content:
application/json: {}
responses:
"201":
description: Order created.
content:
application/json: {}Why:Neither body declares a schema or example, so the expected format is undefined and no tooling can describe or validate it.
For APIs where fields can be mutually exclusive, API producers should provide correct examples to consumers on how to use the API.
requestBody:
content:
application/json:
schema:
oneOf:
- $ref: "#/components/schemas/PriceByAmount"
- $ref: "#/components/schemas/PriceByPercentage"
examples:
byAmount:
value: { amount: 500 }
byPercentage:
value: { percentage: 10 }Why:Each mutually exclusive variant has its own example, so a consumer sees a valid payload for each branch instead of guessing which fields combine.
requestBody:
content:
application/json:
schema:
oneOf:
- $ref: "#/components/schemas/PriceByAmount"
- $ref: "#/components/schemas/PriceByPercentage"
example:
amount: 500
percentage: 10Why:A single example sets both mutually exclusive fields at once, modeling an invalid payload and misleading consumers about how the variants are used.
Find request and response bodies whose schema uses
oneOfor otherwise marks fields as mutually exclusive.For each, check that examples demonstrate a valid combination for every branch and never set mutually exclusive fields together.
Report bodies that lack per-variant examples or whose example violates the exclusivity constraint.
For APIs that respond with plain text, for example CSV, API producers must provide an example, since some tools are not able to generate examples for such responses.
responses:
"200":
description: Export of all invoices as CSV.
content:
text/csv:
schema:
type: string
example: |
id,total,status
inv_1,500,PAID
inv_2,750,OPENWhy:The plain-text response carries an explicit example, so tooling that cannot synthesize one still shows consumers the expected output.
responses:
"200":
description: Export of all invoices as CSV.
content:
text/csv:
schema:
type: stringWhy:A bare
type: stringgives tooling nothing to render for a CSV body, leaving consumers without a sample of the format.
See schema example.
Default values
API producers must document default values.
properties:
pageSize:
type: integer
description: Number of items returned per page.
default: 100Why:The field declares its default with
default, so a consumer who omits it knows the value that applies.properties:
pageSize:
type: integer
description: Number of items returned per page. Defaults to 100 if omitted.Why:The default is buried in prose rather than declared with
default, so tooling and generated clients cannot surface or validate it.Identify properties and parameters whose description or behavior implies a value that applies when the field is omitted.
Confirm each such field declares that value with the
defaultkeyword rather than only mentioning it in prose.Report fields that have an implicit default but no
defaultkeyword.
See Default Values.
Validation Keywords
API producers must detail the required or optional nature of the field and any conditions in both responses and requests.
components:
schemas:
Order:
type: object
required: [customerId, total]
properties:
customerId:
type: string
total:
type: integer
note:
type: stringWhy:The
requiredlist states which fields must be present, so a consumer knows exactly what each request and response guarantees.components:
schemas:
Order:
type: object
properties:
customerId:
type: string
total:
type: integer
note:
type: stringWhy:With no
requiredlist a consumer cannot tell which fields are mandatory, leaving the contract ambiguous in both directions.For each request and response schema, list its properties.
Confirm the schema marks mandatory fields with
requiredand that conditional requirements are documented in the description or schema composition.Report schemas where the required or optional status of a field cannot be determined from the spec.
API producers should avoid overly specific patterns, since changes to a pattern can be considered a breaking change.
properties:
slug:
type: string
pattern: "^[a-zA-Z0-9][a-zA-Z0-9-]*$"Why:A broad shape constraint validates input without locking the API into details that may need to loosen later.
properties:
slug:
type: string
pattern: "^(prod|stg|dev)-[a-z]{3}-[0-9]{4}$"Why:A pattern that encodes exact prefixes and lengths must change whenever those details evolve, and tightening or loosening it is a breaking change.
- Collect every
patternconstraint in the spec. Flag patterns that encode narrow business specifics — fixed prefixes, exact lengths, enumerated segments — rather than a general shape.
Report each overly specific pattern, since later edits to it would break existing clients.
- Collect every
For numeric values API producers may document minimum, exclusive minimum, maximum, and exclusive maximum.
See validations for a full list of available validations.
Operation Summary
Operation summaries are titles describing an API operation.
Operation summaries must be concise.
paths:
/orders/{orderId}:
get:
summary: Return One OrderWhy:A short title names the operation at a glance, which is all a summary is for.
paths:
/orders/{orderId}:
get:
summary: >-
Return One Order by Its Identifier Including All Line Items and the
Current Shipping Status for the Authenticated CallerWhy:A summary stuffed with behavioral detail stops being a title; that detail belongs in the description.
- For each operation, read its
summary. Confirm the summary is a short title — roughly a noun phrase, not a sentence of behavioral detail.
Report summaries that carry usage detail or nuance that belongs in the description.
- For each operation, read its
Operation summaries should describe what an operation does, but should not describe in-depth information about how to use it or nuances in behavior. For additional details about the behavior of the operations, refer to Descriptions.
paths:
/projects/{projectId}/members:
post:
summary: Add One Member to One Project
description: >-
Adds a member to the project. The caller must have the project owner
role. Members added this way inherit the default project role.Why:The summary states what the operation does; the how-to-use detail lives in the description where consumers expect it.
paths:
/projects/{projectId}/members:
post:
summary: >-
Add One Member to One Project, Which Requires the Owner Role and Applies
the Default Project Role to the New MemberWhy:The summary absorbs behavioral nuance that belongs in the description, so it no longer reads as a title.
For each operation, read its
summaryanddescription.Confirm the summary states what the operation does and that usage detail or behavioral nuance lives in the description instead.
Report summaries that carry how-to-use or edge-case detail.
Formatting
Summaries must use Title Case.
paths:
/orders/{orderId}:
get:
summary: Return One OrderWhy:Title Case matches the convention used for every operation title in the reference.
paths:
/orders/{orderId}:
get:
summary: Return one orderWhy:Sentence case breaks the consistent title styling readers rely on to scan the operation list.
Summaries must not end with a period.
paths:
/orders/{orderId}:
get:
summary: Return One OrderWhy:A title is not a sentence, so it carries no terminating punctuation.
paths:
/orders/{orderId}:
get:
summary: Return One Order.Why:A trailing period treats the title as a sentence and diverges from the rest of the operation list.
Summaries must not use CommonMark.
paths:
/orders/{orderId}:
get:
summary: Return One OrderWhy:A plain-text title renders identically everywhere a summary appears.
paths:
/orders/{orderId}:
get:
summary: Return One `Order`Why:Markdown in a title surfaces as literal backticks or markup in tools that do not render CommonMark in summary fields.
Language
API producers must use "One" when referring to a single item instead of "a" or "specified".
paths:
/orders/{orderId}:
get:
summary: Return One OrderWhy:"One" states the cardinality plainly and matches the wording used for every single-item operation.
paths:
/orders/{orderId}:
get:
summary: Return a Specified OrderWhy:"a" and "Specified" are vaguer and inconsistent ways to say the same thing that "One" expresses directly.
API producers must use "Return" instead of "Get" or "List".
paths:
/orders:
get:
summary: Return All OrdersWhy:"Return" is the single read verb used across the API, so consumers scan for one word rather than several synonyms.
paths:
/orders:
get:
summary: List OrdersWhy:"List" and "Get" are interchangeable synonyms for the same read action and fragment the vocabulary consumers must learn.
API producers must not use "Return All" unless the API can really return all items in a collection. Collections may contain an unbounded number of entries and must be paginated (see Pagination); if the total number of entries can exceed the page size and prevent the client from accessing the full set, do not use "All".
paths:
/orders:
get:
summary: Return All Orders
description:
Returns every order. The result set is bounded and not paginated.Why:"All" is accurate only because the operation genuinely returns the entire bounded collection in one response.
paths:
/orders:
get:
summary: Return All Orders
parameters:
- name: pageNum
in: query
schema:
type: integer
- name: itemsPerPage
in: query
schema:
type: integerWhy:The operation is paginated, so a single call returns one page rather than every order; "All" overstates what the consumer receives.
Find get operations whose summary starts with "Return All".
For each, determine whether the operation is paginated or otherwise capped below the full collection size — look for page or limit parameters and the response envelope.
Report any "Return All" summary on an operation that cannot return the entire collection in one response.
Depends onAPI producers must use "Update" instead of "Modify" or "Change".
paths:
/orders/{orderId}:
patch:
summary: Update One OrderWhy:"Update" is the single mutation verb used across the API for editing an existing resource.
paths:
/orders/{orderId}:
patch:
summary: Modify One OrderWhy:"Modify" and "Change" are synonyms for "Update" that add vocabulary without adding meaning.
API producers should use "Delete" when the operation is destroying a resource, and should use "Remove" when the resource itself is not being destroyed.
paths:
/orders/{orderId}:
delete:
summary: Delete One Order
/projects/{projectId}/members/{userId}:
delete:
summary: Remove One Member from One ProjectWhy:"Delete" marks the destruction of the order, while "Remove" marks disassociating a member who continues to exist, so the verb signals the effect.
paths:
/projects/{projectId}/members/{userId}:
delete:
summary: Delete One Member from One ProjectWhy:"Delete" implies the member is destroyed, but the operation only removes the member from the project, so "Remove" is the accurate verb.
API producers should use "Create" when the operation is creating a resource, and should use "Add" when the resource itself is not being created.
paths:
/orders:
post:
summary: Create One Order
/projects/{projectId}/members:
post:
summary: Add One Member to One ProjectWhy:"Create" marks bringing a new order into existence, while "Add" marks associating an existing user with a project, so the verb signals the effect.
paths:
/projects/{projectId}/members:
post:
summary: Create One Member in One ProjectWhy:"Create" implies a new member resource is brought into being, but the operation only associates an existing user, so "Add" is the accurate verb.
API producers must use "Reset" when the operation is restoring a resource to its default state.
paths:
/projects/{projectId}/settings:reset:
post:
summary: Reset Settings for One ProjectWhy:"Reset" names the effect precisely: the settings return to their default state rather than being edited or removed.
paths:
/projects/{projectId}/settings:reset:
post:
summary: Update Settings for One Project to DefaultWhy:"Update" describes an arbitrary edit, hiding that the operation restores the default state, which "Reset" conveys directly.
Find operations whose behavior restores a resource to its default state.
Confirm each such summary uses "Reset" rather than "Update" or another verb.
Report restore-to-default operations whose summary uses a different verb.
API producers must use only one main action verb, for example "Create", "Update", "Delete", "Add", or "Remove".
paths:
/orders/{orderId}:
patch:
summary: Update One OrderWhy:A single action verb states exactly one effect, so the summary is unambiguous.
paths:
/orders/{orderId}:
patch:
summary: Update and Reset One OrderWhy:Two action verbs describe two effects in one title, leaving a consumer unsure what the operation actually does.
For each operation, read its
summaryand identify the action verbs it contains.Confirm exactly one main action verb is present.
Report summaries that chain more than one action verb.
API producers must not use abbreviations and technical formatting in summaries — for example "Line Items" instead of "lineItems", "Organization Configuration" instead of "Org Config", and "Feature Compatibility Version" instead of "FCV".
paths:
/orders/{orderId}/line-items:
get:
summary: Return All Line Items for One OrderWhy:Spelled-out words in normal title casing read as prose to any consumer, not as code identifiers.
paths:
/orders/{orderId}/line-items:
get:
summary: Return All lineItems for One OrderWhy:A camelCase identifier and a code-style abbreviation leak technical formatting into a human-facing title.
- For each operation, read its
summary. Flag camelCase or snake_case identifiers, code-style tokens, and unexpanded abbreviations.
Report summaries that use technical formatting where spelled-out words belong.
- For each operation, read its
API producers must use "by" when referring to how something should be queried — for example "Return One Event by ID" instead of "Return One Event Using Its ID".
paths:
/events/{eventId}:
get:
summary: Return One Event by IDWhy:"by" is the consistent connector for query criteria across the API.
paths:
/events/{eventId}:
get:
summary: Return One Event Using Its IDWhy:"Using Its" is a wordier connector that says the same thing as "by" and breaks the consistent phrasing.
Find summaries that name the criterion used to select a resource.
Confirm the connector is "by" rather than a wordier phrase such as "using its" or "with".
Report summaries that express query criteria with a connector other than "by".
API producers must use "in" for actions operating within the parent (retrieving, updating, creating) and "from" for removing or disassociating — for example "Update One Member in One Project" and "Remove One Member from One Project".
paths:
/projects/{projectId}/members/{userId}:
patch:
summary: Update One Member in One Project
delete:
summary: Remove One Member from One ProjectWhy:"in" marks an action within the parent and "from" marks disassociation, so the preposition signals the relationship the operation has with the parent.
paths:
/projects/{projectId}/members/{userId}:
delete:
summary: Remove One Member in One ProjectWhy:"in" describes acting within the project, but removal disassociates the member from it, so "from" is the accurate preposition.
Find summaries that relate a sub-resource to a parent resource.
For each, check the preposition: "in" for retrieving, updating, or creating within the parent; "from" for removing or disassociating.
Report summaries whose preposition does not match the action.
API producers should avoid unnecessary filler words, for example "possible", "available", or "current".
paths:
/orders:
get:
summary: Return All OrdersWhy:Every word in the title carries meaning, so nothing distracts from what the operation does.
paths:
/orders:
get:
summary: Return All Currently Available OrdersWhy:"Currently" and "Available" add no information beyond "Return All Orders" and pad the title.
- For each operation, read its
summary. Flag filler words such as "possible", "available", or "current" that do not change the meaning of the title.
- Report summaries that carry such filler.
- For each operation, read its