An OpenAPI specification example is a complete, valid OpenAPI 3.x file you can paste into Swagger UI, Redoc, or any spec parser and have it render straight away. This page collects four of them: a minimal one-endpoint API, a REST CRUD service for /users, an authenticated API with OAuth2 plus API key, and a webhook callback definition. Every file below is valid OpenAPI 3.0.3 or 3.1.0 YAML. Copy any block, save it as openapi.yaml, and load it in your favorite tool. For the conceptual side, the complete guide to OpenAPI documentation explains what the spec is and why it matters before you wire one up.
Key takeaways
- An OpenAPI specification example must include four required root keys:
openapi,info, and one ofpathsorcomponents. Everything else is optional.- YAML is preferred for hand-authored specs; JSON is preferred for machine-generated ones. Both are equally valid.
- The four examples below cover the patterns most teams need: minimal, CRUD, secured, and webhooks.
- Tools like Swagger UI, Redoc, Stoplight, and Docsio's AI doc generator turn any of these YAML files into a hosted developer portal.
If you just need a starting point you can adapt, jump straight to the REST CRUD example below. Otherwise the next section gives you the structure first so the YAML reads cleanly.
What is an OpenAPI specification?
An OpenAPI specification is a machine-readable description of a REST API written in YAML or JSON. It defines every endpoint, request shape, response shape, authentication method, and error model your API exposes, in a format any tool can parse. The spec is governed by the OpenAPI Initiative under the Linux Foundation and is currently at version 3.1.0, which aligns the JSON Schema dialect with the latest IETF draft.
The format started life as Swagger in 2011 and was donated to the Linux Foundation in 2015. Today, 93% of developers still ship REST APIs (Postman State of the API, 2025), which keeps OpenAPI as the default contract for nearly every public and internal HTTP API.
A working spec acts as a single source of truth. Frontend teams generate TypeScript clients from it. QA generates Postman collections. Documentation tools render it as a portal. AI tools read it to answer questions about your API. Get the spec right and the rest falls out of it.
Anatomy of an OpenAPI specification
Every OpenAPI specification example you will see below shares the same five top-level sections. Knowing what each one does makes the YAML feel less like an alphabet soup.
openapi: the version of the spec format itself. Use3.0.3for maximum tool support,3.1.0for newer JSON Schema features.info: metadata about your API: title, version, description, contact, license. Required.servers: base URLs where the API is reachable. Optional but strongly recommended.paths: every endpoint, keyed by URL pattern, then by HTTP method. This is where most of your spec lives.components: reusable schemas, parameters, responses, and security schemes. Define a model once, reference it everywhere with$ref.
A spec must include openapi, info, and one of paths or components. Everything else is optional. With those rules in mind, here is the smallest valid OpenAPI specification example.
OpenAPI specification example: a minimal API
This is the smallest spec that still does something useful. One endpoint, one response, no auth. If Swagger UI loads this without errors, your YAML formatting is correct.
openapi: 3.0.3
info:
title: Hello API
version: 1.0.0
description: The smallest valid OpenAPI specification example.
servers:
- url: https://api.example.com/v1
paths:
/hello:
get:
summary: Return a greeting
operationId: getHello
responses:
'200':
description: A friendly greeting
content:
application/json:
schema:
type: object
properties:
message:
type: string
example: Hello, world
example:
message: Hello, world
Save that as openapi.yaml, drop it into editor.swagger.io, and you get a rendered reference page with a "Try it out" button. That is the floor. Real APIs add models, parameters, and authentication, which is what the next three examples cover.
OpenAPI specification example: REST CRUD API
The pattern below is the one most engineers actually need: full CRUD on a /users resource with shared schemas in components. This is the spec you should copy first when starting a new service. It demonstrates path parameters, request bodies, multiple response codes, and $ref reuse, all of which line up with API reference documentation best practices.
openapi: 3.0.3
info:
title: Users API
version: 1.2.0
description: REST CRUD OpenAPI specification example for a users resource.
contact:
name: API Support
email: api@example.com
servers:
- url: https://api.example.com/v1
paths:
/users:
get:
summary: List users
operationId: listUsers
parameters:
- name: limit
in: query
schema:
type: integer
minimum: 1
maximum: 100
default: 20
- name: cursor
in: query
schema:
type: string
responses:
'200':
description: A page of users
content:
application/json:
schema:
type: object
properties:
data:
type: array
items:
$ref: '#/components/schemas/User'
next_cursor:
type: string
nullable: true
post:
summary: Create a user
operationId: createUser
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/UserCreate'
responses:
'201':
description: Created
content:
application/json:
schema:
$ref: '#/components/schemas/User'
'400':
$ref: '#/components/responses/BadRequest'
/users/{id}:
parameters:
- name: id
in: path
required: true
schema:
type: string
format: uuid
get:
summary: Get user by id
operationId: getUser
responses:
'200':
description: A single user
content:
application/json:
schema:
$ref: '#/components/schemas/User'
'404':
$ref: '#/components/responses/NotFound'
put:
summary: Replace a user
operationId: replaceUser
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/UserCreate'
responses:
'200':
description: Updated
content:
application/json:
schema:
$ref: '#/components/schemas/User'
delete:
summary: Delete a user
operationId: deleteUser
responses:
'204':
description: Deleted
components:
schemas:
User:
type: object
required: [id, email, created_at]
properties:
id:
type: string
format: uuid
email:
type: string
format: email
name:
type: string
created_at:
type: string
format: date-time
UserCreate:
type: object
required: [email]
properties:
email:
type: string
format: email
name:
type: string
responses:
BadRequest:
description: Validation failed
content:
application/json:
schema:
type: object
properties:
error:
type: string
example: invalid_email
NotFound:
description: Resource not found
content:
application/json:
schema:
type: object
properties:
error:
type: string
example: not_found
A few details that matter. Path parameters are declared once on the path object, not repeated on every method. The UserCreate schema is separate from User because clients should not send id or created_at. Reusable error responses live under components.responses and get $ref'd into each operation, which keeps the spec roughly half its naive size. If you want a real Petstore-style reference to compare against, the OpenAPI Initiative hosts one at learn.openapis.org.
OpenAPI specification example: authenticated API
Most production APIs use either an API key or OAuth2. The next OpenAPI specification example shows both, plus a structured error response. Copy this when your service is past the prototype stage.
openapi: 3.0.3
info:
title: Billing API
version: 2.0.0
description: Authenticated OpenAPI specification example with OAuth2 and API key.
servers:
- url: https://api.example.com/v2
security:
- oauth2: [read, write]
- apiKey: []
paths:
/invoices:
get:
summary: List invoices
operationId: listInvoices
security:
- oauth2: [read]
- apiKey: []
responses:
'200':
description: A list of invoices
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Invoice'
'401':
$ref: '#/components/responses/Unauthorized'
'403':
$ref: '#/components/responses/Forbidden'
'429':
$ref: '#/components/responses/RateLimited'
post:
summary: Create an invoice
operationId: createInvoice
security:
- oauth2: [write]
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/InvoiceCreate'
responses:
'201':
description: Created
content:
application/json:
schema:
$ref: '#/components/schemas/Invoice'
'422':
$ref: '#/components/responses/ValidationError'
components:
securitySchemes:
oauth2:
type: oauth2
flows:
authorizationCode:
authorizationUrl: https://auth.example.com/authorize
tokenUrl: https://auth.example.com/token
scopes:
read: Read access to billing resources
write: Write access to billing resources
apiKey:
type: apiKey
in: header
name: X-API-Key
schemas:
Invoice:
type: object
required: [id, amount_cents, currency, status]
properties:
id:
type: string
amount_cents:
type: integer
minimum: 0
currency:
type: string
enum: [USD, EUR, GBP]
status:
type: string
enum: [draft, open, paid, void]
created_at:
type: string
format: date-time
InvoiceCreate:
type: object
required: [amount_cents, currency]
properties:
amount_cents:
type: integer
minimum: 1
currency:
type: string
enum: [USD, EUR, GBP]
Error:
type: object
required: [code, message]
properties:
code:
type: string
message:
type: string
request_id:
type: string
responses:
Unauthorized:
description: Missing or invalid credentials
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
code: unauthorized
message: API key is missing or invalid
request_id: req_abc123
Forbidden:
description: Authenticated but not allowed
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
RateLimited:
description: Rate limit exceeded
headers:
Retry-After:
schema:
type: integer
description: Seconds before the next allowed request
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
ValidationError:
description: Request body failed validation
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
The top-level security block sets the default for every operation; the per-operation security overrides it when an endpoint needs different scopes. Two equally valid auth options on the same endpoint are expressed as two array entries (OAuth2 OR API key); requiring both at once would be one entry with both keys. Error responses share a single Error schema so clients only have to learn one shape. The Retry-After header on the 429 response is the small detail that turns a working spec into one that is actually pleasant to integrate against.
OpenAPI specification example: webhook callbacks
Webhooks were a second-class citizen in OpenAPI 3.0. The 3.1 spec added a top-level webhooks key that is the right way to document them today. The example below shows both styles: the modern 3.1 webhooks block and the legacy callbacks pattern that still appears in older codebases. If you also need the long version of how to document webhook payloads, see how to document webhooks properly.
openapi: 3.1.0
info:
title: Payments API
version: 1.0.0
description: Webhook OpenAPI specification example using the 3.1 webhooks key.
servers:
- url: https://api.example.com/v1
paths:
/subscriptions:
post:
summary: Subscribe to webhook events
operationId: createSubscription
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [url, events]
properties:
url:
type: string
format: uri
events:
type: array
items:
type: string
enum: [payment.succeeded, payment.failed]
responses:
'201':
description: Subscription created
webhooks:
paymentSucceeded:
post:
summary: Sent when a payment succeeds
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/PaymentEvent'
responses:
'200':
description: Acknowledged. Return 2xx within 5 seconds or we retry.
'410':
description: Endpoint gone. We will stop sending after 410.
paymentFailed:
post:
summary: Sent when a payment fails
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/PaymentEvent'
responses:
'200':
description: Acknowledged
components:
schemas:
PaymentEvent:
type: object
required: [id, type, created, data]
properties:
id:
type: string
example: evt_1abc
type:
type: string
enum: [payment.succeeded, payment.failed]
created:
type: integer
description: Unix timestamp
data:
type: object
properties:
payment_id:
type: string
amount_cents:
type: integer
currency:
type: string
The webhooks block lives at the root, alongside paths. Each entry describes the request your server sends to the subscriber, plus the responses you expect back. Tools like Redoc and Stoplight render webhooks as their own section in the developer portal; older tools that only know 3.0 silently ignore the block, so for maximum compatibility, document webhook semantics in prose too.
YAML vs JSON for OpenAPI
Both formats are equally valid for OpenAPI specs. Pick one based on who is editing the file.
| Dimension | YAML | JSON |
|---|---|---|
| Readability | Cleaner; no quoting noise | Heavier punctuation |
| Human authoring | Preferred | Painful at scale |
| Machine generation | Common but not standard | Default for code generators |
| Comments | Supported | Not supported |
| Tool support | Universal | Universal |
| Common file name | openapi.yaml | openapi.json |
YAML wins for hand-written specs because of comments and lower visual noise. JSON wins for specs emitted by frameworks like FastAPI or NestJS, since those frameworks already serialize via JSON Schema. Some teams keep both: YAML in the repo for editing, a JSON build artifact for tooling that requires it. Either works.
Tools that use OpenAPI specs
A spec on its own is just a file. The tooling layer turns it into a developer portal, a client library, or a test suite. The most common renderers fall into four buckets.
- Swagger UI: the original. Free, open source, ubiquitous. Renders any 3.x spec into an interactive reference with a "Try it out" panel.
- Redoc: a more polished single-page renderer that powers the docs at GitHub, Docker, and many large APIs.
- Stoplight: a hosted platform with a visual spec editor, mock server, and rendered docs. Good for teams that want to design the spec before writing code.
- Mintlify and ReadMe: hosted docs platforms that consume an OpenAPI file and render a branded developer portal. Both start at $300+/mo, which is heavy for a small SaaS.
- Docsio: feeds your OpenAPI spec or product URL into AI generation and ships a branded, hosted docs site in under five minutes. $60/mo per site for Pro features, free tier with one site, custom domain, and SSL.
For the wider category, the API documentation tool roundup compares the major options across price and setup time. If you only have an OpenAPI spec and want a working portal today, the AI generation flow handles ingestion, branding, and hosting in one pass.
Common mistakes in OpenAPI specs
These are the issues that show up over and over in spec reviews, in the order they cause the most pain.
- Missing
operationIdon operations. Code generators useoperationIdas the function name. Skip it and your generated SDK gets ugly auto-named methods likeusersUserIdGetGet. Always set it. - Inlining the same schema everywhere. A
Userobject copy-pasted into ten responses is a nightmare to update. Define it once undercomponents.schemasand$refit. - Forgetting the
requiredarray on object schemas. Withoutrequired, every property is optional, which silently breaks generated clients that expect non-null fields. - Mixing 3.0 and 3.1 features. Tools that target 3.0 will fail on
webhooksor JSON Schema 2020-12 keywords. Pick a version and stick to it. - No
serversblock. Without it,Try it outpanels in Swagger UI default to the docs site URL, which is almost never the API origin. Always declare at least one server. - Vague descriptions. "User object" is not a description. State what the field means, what units it uses, and what edge cases exist. The spec is the developer's primary reference, not a side note.
- Hand-edited specs that drift from the code. Once the team is past 20 endpoints, the spec stops matching the implementation. Generate from code (FastAPI, NestJS, tsoa) or use a contract-first lint check in CI.
Fix those seven and the average OpenAPI spec quality jumps from "barely loads" to "I would actually integrate against this."
Frequently asked questions
What is a simple example of an OpenAPI specification?
The minimal valid OpenAPI specification example needs three keys at the root: openapi: 3.0.3, an info block with title and version, and either paths or components. A single GET endpoint that returns { message: "Hello, world" } is enough to load in Swagger UI and demonstrates every required structural piece.
Should I write OpenAPI in YAML or JSON?
YAML is preferred for hand-authored specs because it allows comments and reads more cleanly. JSON is preferred when the spec is generated by a framework like FastAPI or NestJS, since those tools already serialize via JSON Schema. Both formats are equally valid OpenAPI; tools accept either.
What is the difference between OpenAPI 3.0 and 3.1?
OpenAPI 3.1 aligns the schema dialect with JSON Schema 2020-12 and adds a top-level webhooks block. 3.0 is more widely supported by older tooling. For a new project, write 3.1 if your renderer supports it; otherwise 3.0.3 is the safe default with maximum compatibility.
Where can I find a working Petstore OpenAPI example?
The official Petstore spec lives at github.com/swagger-api/swagger-petstore and the OpenAPI Initiative hosts a curated set at learn.openapis.org. The CRUD example earlier in this article is a leaner version that demonstrates the same patterns in a smaller file.
How do I turn an OpenAPI spec into a documentation site?
Load the spec into a renderer. Swagger UI and Redoc are free and open source. Stoplight and Mintlify are hosted SaaS options. Docsio takes an OpenAPI spec or a product URL and generates a branded, hosted docs site automatically with one click of publish.
Putting an OpenAPI specification example to work
You now have four valid OpenAPI specification examples plus the patterns that matter most: shared schemas with $ref, structured error responses, OAuth2 plus API key, and webhook callbacks. The next step is rendering one of them. If you want a hosted developer portal without spending a weekend wiring up Docusaurus, point Docsio's AI generator at your spec or product URL and you have a branded site live in under five minutes. The free tier covers a single site with custom domain and SSL.
For the broader category and how OpenAPI fits into the rest of your docs stack, the API documentation best practices guide is the right next read.
