OpenAPI 3

Standards Security Notes Jan 9, 2026 YAML
openapi api-specification standards json-schema callbacks webhooks

Definition

OpenAPI 3.x represents a major evolution from Swagger 2.0, bringing modern API patterns into the specification. Released in 2017, OpenAPI 3.0 introduced support for callbacks (webhooks), multiple request/response examples, improved authentication models, and cleaner schema composition. OpenAPI 3.1 (2021) went further by achieving full compatibility with JSON Schema Draft 2020-12, making it easier to reuse schemas across different tools and specifications.

The 3.x series fundamentally changed how complex APIs are described. You can now model webhook subscriptions, define multiple servers for different environments, use discriminators for polymorphic responses, and leverage the full power of JSON Schema including conditionals, dependencies, and advanced validation rules.

Unlike Swagger 2.0, which was tightly coupled to the Swagger tooling ecosystem, OpenAPI 3.x is designed to be tool-agnostic. This has led to an explosion of compatible tools for documentation, code generation, testing, and API gateways from various vendors and open-source projects.

Example

Webhook Definition: Stripe uses OpenAPI 3.x to document their webhook callbacks. When you subscribe to payment events, Stripe defines the exact schema of webhook payloads using the callbacks feature - something impossible in Swagger 2.0.

Polymorphic Schemas: GitHub’s API uses discriminators to model different event types (PushEvent, IssueEvent, PullRequestEvent) that share a base structure but have type-specific fields. OpenAPI 3.x’s discriminator feature makes this clear to both humans and code generators.

Multiple Examples: Twilio documents various request scenarios using OpenAPI 3.x’s multiple examples feature. For sending an SMS, they show examples with different parameters - simple text, media messages, scheduled sending - all within a single endpoint definition.

Environment-Specific Servers: AWS services define multiple server URLs in their OpenAPI specs - production, staging, regional endpoints - letting tools automatically switch between environments without manual URL changes.

oneOf/anyOf Composition: Payment gateway APIs use oneOf to model different payment methods (credit card, bank transfer, digital wallet) where each has unique required fields. OpenAPI 3.x’s schema composition handles this elegantly.

Analogy

The Upgraded Instruction Manual: If Swagger 2.0 was like a basic instruction manual with linear steps, OpenAPI 3.x is the premium version with fold-out diagrams, multiple scenario guides, and QR codes linking to video tutorials. It doesn’t just tell you how to use the product - it models complex interactions like subscription services (webhooks) and customization options (polymorphic schemas).

The Multi-Environment GPS: Swagger 2.0 was like a GPS with one map. OpenAPI 3.x is like having multiple map layers (satellite, traffic, terrain) and saved locations for home/work/vacation. The multiple servers feature is like having preset destinations for different contexts - all in one system.

The Choose-Your-Own-Adventure Book: OpenAPI 3.x’s schema composition (oneOf, anyOf, allOf) is like a choose-your-own-adventure story. Depending on your choices (discriminator field), different paths (schemas) become available. Swagger 2.0 was a linear novel - one story, one path.

Code Example


openapi: 3.1.0
info:
  title: Payment Processing API
  version: 2.0.0

servers:
  - url: https://api.payment.com/v2
    description: Production
  - url: https://sandbox.payment.com/v2
    description: Sandbox

paths:
  /payments:
    post:
      summary: Create a payment
      requestBody:
        content:
          application/json:
            schema:
              oneOf:
                - $ref: '#/components/schemas/CreditCardPayment'
                - $ref: '#/components/schemas/BankTransferPayment'
                - $ref: '#/components/schemas/DigitalWalletPayment'
              discriminator:
                propertyName: paymentMethod
                mapping:
                  credit_card: '#/components/schemas/CreditCardPayment'
                  bank_transfer: '#/components/schemas/BankTransferPayment'
                  digital_wallet: '#/components/schemas/DigitalWalletPayment'
            examples:
              creditCard:
                summary: Credit card payment
                value:
                  paymentMethod: credit_card
                  amount: 99.99
                  currency: USD
                  cardNumber: "4111111111111111"
                  expiryDate: "12/25"
                  cvv: "123"
              bankTransfer:
                summary: Bank transfer
                value:
                  paymentMethod: bank_transfer
                  amount: 500.00
                  currency: EUR
                  iban: "DE89370400440532013000"
                  bic: "COBADEFFXXX"
      responses:
        '201':
          description: Payment created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PaymentResponse'
      callbacks:
        paymentStatus:
          '{$request.body#/callbackUrl}':
            post:
              summary: Payment status update
              requestBody:
                content:
                  application/json:
                    schema:
                      $ref: '#/components/schemas/PaymentWebhook'
              responses:
                '200':
                  description: Webhook received

components:
  schemas:
    CreditCardPayment:
      type: object
      required: [paymentMethod, amount, currency, cardNumber]
      properties:
        paymentMethod:
          type: string
          const: credit_card
        amount:
          type: number
          minimum: 0.01
        currency:
          type: string
          pattern: "^[A-Z]{3}$"
        cardNumber:
          type: string
          pattern: "^[0-9]{13,19}$"
        expiryDate:
          type: string
          pattern: "^(0[1-9]|1[0-2])/[0-9]{2}$"
        cvv:
          type: string
          pattern: "^[0-9]{3,4}$"

    BankTransferPayment:
      type: object
      required: [paymentMethod, amount, currency, iban]
      properties:
        paymentMethod:
          type: string
          const: bank_transfer
        amount:
          type: number
        currency:
          type: string
        iban:
          type: string
        bic:
          type: string

    DigitalWalletPayment:
      type: object
      required: [paymentMethod, amount, walletProvider, walletToken]
      properties:
        paymentMethod:
          type: string
          const: digital_wallet
        amount:
          type: number
        walletProvider:
          type: string
          enum: [paypal, apple_pay, google_pay]
        walletToken:
          type: string

    PaymentResponse:
      type: object
      properties:
        id:
          type: string
          format: uuid
        status:
          type: string
          enum: [pending, completed, failed]
        createdAt:
          type: string
          format: date-time

    PaymentWebhook:
      type: object
      properties:
        eventType:
          type: string
          enum: [payment.completed, payment.failed]
        paymentId:
          type: string
        timestamp:
          type: string
          format: date-time

  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-Key
    OAuth2:
      type: oauth2
      flows:
        authorizationCode:
          authorizationUrl: https://auth.payment.com/oauth/authorize
          tokenUrl: https://auth.payment.com/oauth/token
          scopes:
            payments:write: Create payments
            payments:read: Read payment status

security:
  - ApiKeyAuth: []
  - OAuth2: [payments:write]

Diagram

graph TB
    subgraph "OpenAPI 3.x Features"
        subgraph "Core Improvements"
            SERVERS[Multiple Servers
Prod, Staging, Regional] EXAMPLES[Multiple Examples
Per Content Type] LINKS[Links
Operation Chaining] end subgraph "Schema Enhancements" ONEOF[oneOf/anyOf/allOf
Composition] DISC[Discriminator
Polymorphism] JSON[Full JSON Schema
v2020-12 in 3.1] end subgraph "Advanced Patterns" CALLBACKCallbacks
[Webhooks] COOKIE[Cookie Auth
Parameters] COMP[Reusable Components
Headers, Examples] end end API[API Definition] --> SERVERS API --> EXAMPLES API --> ONEOF API --> CALLBACK style JSON fill:#90EE90 style CALLBACK fill:#FFD700 style DISC fill:#87CEEB

Security Notes

SECURITY NOTES

CRITICAL: OpenAPI defines API contract. Validate requests/responses against schema.

Schema Definition:

  • Endpoints: Define all endpoints and methods
  • Parameters: Document query, path, and header parameters
  • Request body: Define request payload schema
  • Response body: Define response payload schema
  • Status codes: Document all status codes

Security Definitions:

  • Authentication: Define security schemes (OAuth, API key, etc.)
  • Authorization scopes: Define required scopes per operation
  • Security requirements: Specify which operations need auth
  • TLS: Document TLS requirements

Validation Benefits:

  • Contract enforcement: Validate requests/responses match schema
  • API documentation: Auto-generate documentation
  • Code generation: Generate client/server stubs
  • Testing: Generate test cases from schema

API Evolution:

  • Backward compatible: Maintain compatibility with old versions
  • Deprecation: Mark deprecated fields/endpoints
  • Versioning: Version API alongside schema
  • Migration: Provide migration paths for clients

Best Practices

  1. Use discriminator for polymorphism - When oneOf represents different types, add a discriminator to help code generators
  2. Leverage multiple examples - Provide real-world examples for each scenario, not just success cases
  3. Define callbacks for webhooks - Model webhook payloads as callbacks to generate proper event handlers
  4. Reuse components extensively - Extract common schemas, parameters, responses, examples to components
  5. Use JSON Schema fully in 3.1 - Take advantage of if/then/else, dependencies, and advanced validation
  6. Document authentication flows - Specify OAuth flows, API key locations, and security requirements clearly
  7. Version servers appropriately - Use /v1, /v2 in server URLs rather than in paths
  8. Add operation IDs - These become method names in SDKs, so make them descriptive

Common Mistakes

Mixing 3.0 and 3.1 features: Using JSON Schema features from 3.1 (like prefixItems) in a 3.0 spec causes validation errors. Stick to one version.

Ignoring discriminator: Defining oneOf without discriminator makes code generation harder and error messages cryptic when validation fails.

Overusing anyOf: Using anyOf when oneOf is correct (mutually exclusive types). anyOf means “can match multiple schemas simultaneously”, which is rarely intended for API contracts.

Hardcoding server URLs: Putting environment-specific URLs in example code rather than using the servers array. Tools can’t auto-switch environments.

Skipping callbacks for webhooks: Documenting webhook payloads in prose rather than as proper callbacks means no automatic webhook handler generation.

Not testing spec validity: Publishing specs without running them through validators. OpenAPI 3.x has strict requirements that differ from 2.0.

Incomplete security definitions: Defining securitySchemes but forgetting to apply them via the security property at root or operation level.

Standards & RFCs