
September 08, 2026
10 min read
By Kokil Thapa | Last reviewed: September 2026
An undocumented REST endpoint is a liability waiting to happen. The OpenAPI 3.1 Specification Complete Guide you need starts with a single machine-readable contract that describes paths, schemas, security, and errors before a single controller ships. On production Laravel and Symfony projects I maintain, that contract is what keeps mobile clients, payment webhooks, and third-party integrators aligned when the API evolves. This guide walks through OpenAPI 3.1 from first openapi: 3.1.0 line to validated docs your team can trust — whether you build in Kathmandu or ship globally. For hands-on delivery, see our API development services in Nepal.
openapi: 3.1.0, info, paths, components, and optional webhooks. It aligns schemas with JSON Schema 2020-12, supports nullable types natively, and powers validation, code generation, and interactive docs from one source of truth.What is the OpenAPI 3.1 Specification and how does it differ from 3.0?
OpenAPI 3.1 is the current major line of the OpenAPI Specification (OAS). It was ratified by the OpenAPI Initiative and fully aligns schema definitions with JSON Schema draft 2020-12. That alignment removes years of friction where Swagger tooling and standard JSON Schema validators disagreed on the same field.
The specification itself lives at spec.openapis.org/oas/v3.1.0. Read that document when you need authoritative wording on edge cases. For day-to-day work, most teams author YAML and render it with Swagger UI, Redoc, or Stoplight — a workflow covered in our Redoc and Swagger UI documentation guide.
Breaking changes from OpenAPI 3.0
Three differences matter in daily work. First, schemas use JSON Schema 2020-12 syntax — not the OpenAPI-flavoured subset from 3.0. Second, nullable fields use a type array like ["string", "null"] instead of a separate nullable: true flag. Third, the top-level webhooks object is first-class, which suits event-driven APIs and payment callback designs I use on eSewa and Khalti integrations.
| Feature | OpenAPI 3.0 | OpenAPI 3.1 |
|---|---|---|
| Schema dialect | Custom subset | JSON Schema 2020-12 |
| Nullable fields | nullable: true | type: ["string", "null"] |
| Webhooks | Via callbacks only | Top-level webhooks key |
JSON Schema $schema | Not supported | Allowed in schemas |
| Path templating | Same | Same RFC 6570 rules |
Most tooling now accepts 3.1. Swagger UI 5.x, Redoc 2.x, and Spectral lint both versions. If your CI pipeline still pins Swagger Parser 9.x, upgrade before migrating production specs. Our testing and optimization services often start with a spec audit when client APIs drift from documented behaviour.
How do you structure an OpenAPI 3.1 document from scratch?
Start contract-first. Define the API surface before you write route handlers. On Laravel 13 projects with PHP 8.3 or higher, I keep the spec in docs/openapi.yaml and treat it as the review artefact in pull requests — the same discipline we apply on booking portals like Adventure Third Pole Trek.
Minimal valid skeleton
openapi: 3.1.0
info:
title: Booking API
version: 1.0.0
description: Trek booking endpoints for Nepal operators.
servers:
- url: https://api.example.com/v1
description: Production
paths:
/bookings:
get:
operationId: listBookings
summary: List bookings
responses:
'200':
description: Paginated booking list
content:
application/json:
schema:
$ref: '#/components/schemas/BookingList'
components:
schemas:
BookingList:
type: object
required: [data, meta]
properties:
data:
type: array
items:
$ref: '#/components/schemas/Booking'
meta:
$ref: '#/components/schemas/PaginationMeta'
Booking:
type: object
required: [id, status]
properties:
id:
type: string
format: uuid
status:
type: string
enum: [pending, confirmed, cancelled]
PaginationMeta:
type: object
properties:
page:
type: integer
minimum: 1
per_page:
type: integer
maximum: 100
Paste that YAML into the JSON formatter tool after converting to JSON if you need to debug parser errors. YAML indentation mistakes are the most common first-day failure.
Design rules that save pain later
- Give every operation a unique
operationId— code generators depend on it. - Put shared models under
components.schemas, not inline in each path. - Document all error responses (400, 401, 422, 429, 500) — not just 200.
- Version via URL prefix (
/v1) or header — pick one and document it inservers. - Keep one spec per bounded context; split monoliths into multiple files with
$ref.
For pagination and rate-limit headers, cross-read our API rate limiting guide. Document X-RateLimit-Remaining in response headers so client teams know what to expect.
How do you define schemas and request bodies in OpenAPI 3.1?
Schemas are the heart of any OpenAPI 3.1 Specification Complete Guide section on data modelling. Because 3.1 uses JSON Schema 2020-12, you can use keywords like allOf, oneOf, const, and pattern without vendor quirks.
Nullable and optional fields
In 3.0 you wrote nullable: true. In 3.1, express nullability inside the type array:
properties:
middle_name:
type: ["string", "null"]
maxLength: 100
cancelled_at:
type: ["string", "null"]
format: date-time
Optional but non-null fields omit the field from required — same as before. Do not confuse optional with nullable; a missing key and an explicit null value are different contracts.
Request bodies and content types
paths:
/bookings:
post:
operationId: createBooking
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateBookingRequest'
responses:
'201':
description: Created
content:
application/json:
schema:
$ref: '#/components/schemas/Booking'
'422':
description: Validation failed
content:
application/json:
schema:
$ref: '#/components/schemas/ValidationError'
Mirror your server-side Form Request rules in Laravel. If the spec says maxLength: 255 on email, the PHP validation must match. Mismatch is how mobile apps get surprise 422 responses in production.
Webhooks in 3.1
Payment gateways send server-to-server callbacks. Document them under the top-level webhooks key:
webhooks:
paymentConfirmed:
post:
operationId: onPaymentConfirmed
summary: Gateway notifies successful payment
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/PaymentWebhookPayload'
responses:
'200':
description: Acknowledged
This pattern appears on every eCommerce project where Khalti or Stripe posts back to a Laravel route. The webhook spec is the integration contract your payment partner never reads unless you send it.
How do you document authentication and security in OpenAPI 3.1?
Security belongs in components.securitySchemes and attaches to operations via a security array. Laravel Sanctum bearer tokens and API keys both map cleanly. For a deep comparison of token strategies, read our Passport vs Sanctum authentication guide.
components:
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
apiKeyAuth:
type: apiKey
in: header
name: X-API-Key
paths:
/bookings:
get:
security:
- bearerAuth: []
responses:
'401':
description: Unauthenticated
Document OAuth2 flows only when you actually implement them. An authorizationCode block in the spec without a working /oauth/authorize endpoint misleads integrators and wastes support time.
How do you validate, lint, and test an OpenAPI 3.1 specification?
A spec nobody validates becomes fiction within two sprints. Treat linting and contract tests as CI gates — the same mindset as API contract testing with Pact, but driven from your YAML file.
Lint with Spectral
Install @stoplight/spectral-cli and add a .spectral.yaml ruleset:
extends: ["spectral:oas", "spectral:recommended"]
rules:
operation-operationId: error
operation-description: warn
oas3-valid-media-example: error
Run spectral lint docs/openapi.yaml in GitLab CI before merge. Block deploys on error-level rules.
Validate responses against the spec
- Dredd — HTTP-level tests from OpenAPI examples; good for smoke suites.
- Schemathesis — property-based fuzzing from schemas; catches edge cases.
- openapi-enforcer — Python middleware validation for microservices.
- Laravel response assertions — custom test helper comparing JSON to schema.
On client portals like Mijar Law Associates, document upload endpoints need strict MIME type and size limits in the spec. Fuzz testing catches boundary violations before a lawyer uploads a 40 MB scan on mobile data.
Use the regex tester when defining pattern constraints on Nepali phone numbers or PAN strings. Bad regex in a schema rejects valid input silently at the client SDK layer.
How do you publish and maintain OpenAPI 3.1 documentation?
Generated docs are only as current as your deploy pipeline. Wire spec publication into the same GitLab CI job that ships PHP code on Deployer releases.
Render interactive docs
Swagger UI and Redoc both accept 3.1 when bundled with a current parser. Host static HTML on /api/docs behind auth in staging; public read-only docs for partner APIs on a subdomain like developers.example.com.
Deprecation and versioning
Mark sunset endpoints with deprecated: true on the operation. Add a description pointing to the replacement path and link to our API deprecation best practices for header-based sunset dates.
paths:
/v1/bookings:
get:
deprecated: true
description: |
Sunset: 2026-12-31. Use GET /v2/bookings instead.
responses:
'200':
description: Legacy paginated list
Split large specs using bundlers. @redocly/cli bundle docs/openapi.yaml -o public/api/openapi.json resolves all $ref pointers into one artefact for CDN hosting.
Laravel integration pattern
Laravel 13 does not ship OpenAPI generation natively. Common approaches: hand-author YAML (my preference for public APIs), use darkaonline/l5-swagger for annotation-driven specs, or export from scribe and refine. Annotations drift; contract-first YAML forces design conversations early.
For AI-assisted endpoints, document prompt and response schemas explicitly. Our Claude API developer guide shows why structured output belongs in your spec when LLM responses feed downstream code.
Enterprise teams needing governance across multiple services should read about enterprise application development patterns — one org-wide Spectral ruleset beats per-project conventions.
Key Takeaways
- Set
openapi: 3.1.0and use JSON Schema 2020-12 syntax for everycomponents.schemasentry. - Replace
nullable: truewith type arrays like["string", "null"]when migrating from 3.0. - Assign unique
operationIdvalues and document 4xx/5xx responses on every path. - Run Spectral lint and response validation in CI so the spec cannot drift from production.
- Document webhooks and security schemes explicitly — integrators depend on them.
- Publish bundled specs to Swagger UI or Redoc on every deploy, not as a one-time PDF.
People Also Ask
Is OpenAPI 3.1 backward compatible with 3.0?
Most 3.0 documents upgrade cleanly with mechanical changes to nullable syntax and schema keywords. Tools that only parse 3.0 will reject a 3.1 file outright. Test your parser version before switching the openapi field.
Can OpenAPI 3.1 schemas use full JSON Schema?
Yes, with the constraints noted in the official spec. OpenAPI adds its own keywords like discriminator and ties schemas to HTTP contexts. Pure JSON Schema tooling may not understand those extensions.
What is the best tool to edit OpenAPI 3.1 specs?
VS Code with the OpenAPI (Swagger) Editor extension handles YAML autocomplete well. Stoplight Studio and Insomnia offer visual editing for teams that prefer GUI workflows. Plain Git-tracked YAML remains the most diff-friendly option.
How does OpenAPI relate to Swagger?
Swagger was the original name. The specification was donated to the OpenAPI Initiative and renamed. Swagger UI and Swagger Editor are tools; OpenAPI is the specification format they consume. See the overview at swagger.io/specification.
Ship APIs with a spec your team can trust
You now have a working OpenAPI 3.1 Specification Complete Guide playbook: structure, schemas, auth, webhooks, validation, and publication. The teams that win treat the YAML file as source code — reviewed, linted, tested, and deployed alongside PHP 8.3+ Laravel routes. Whether you are launching a legal-tech portal, a booking API, or a payment integration for Nepal and global markets, start with the contract. Need help authoring or migrating your spec? Contact us for API design and documentation support, or browse the portfolio for production API work. Continue with essential Laravel packages, custom software development, and ongoing API maintenance when your spec outgrows a single file.
Frequently Asked Questions
0 Comments
Leave a comment
Your email is not published. Comments appear once they have been read. Sign in to have your details filled in.

