• Skip to main content
  • Skip to navigation
  • Skip to search
    Petunia™
    FeaturesPricingIntegrationsAboutContact
    Log inStart free trialSign up
    Loading
    Petunia™

    Reimagining customer communication for the modern business.

    Product

    • Features
    • Pricing
    • Integrations
    • Roadmap
    • What's New

    Resources

    • Help Center
    • Documentation
    • Guides
    • API Reference
    • Community
    • Support

    Company

    • About Us
    • Careers
    • Blog
    • Press
    • Contact

    © 2026 Gray Group International LLC. All rights reserved.·
    Made by gardenpatch 🌱

    Privacy PolicyTerms of ServiceCookie Policy

    Petunia™ is a trademark of Gray Group International LLC. The Petunia name, brand, product design, and content are proprietary. Unauthorized use, imitation, or copying is prohibited.

    Documentation

    API_VERSIONING

    docs/API_VERSIONING.md
    Docs homeGuidesSupport
    Quick links
    Start here
    How the docs are organized.
    Environment setup
    Configure env + run locally.
    Unified Inbox
    Inbox concepts & behavior.
    Voice AI setup
    Providers, Twilio, testing.
    Pricing model
    Source-of-truth pricing.
    Operations runbook
    How to operate safely.

    API Versioning Strategy

    Version: 1.0.0 Last Updated: 2025-12-13 Status: Production

    This document outlines Petunia's API versioning strategy, lifecycle management, and migration guidance for API consumers.


    Table of Contents

    1. Overview
    2. Versioning Approach
    3. Version Metadata
    4. Version Lifecycle
    5. Adding New API Versions
    6. Client Migration Guide
    7. Deprecation Process
    8. Examples
    9. Best Practices

    Overview

    Petunia uses a metadata-based versioning approach where API versions are tracked through:

    • File-level JSDoc metadata (@version, @stability)
    • Response headers (X-API-Version, X-Monitoring-Version)
    • OpenAPI specification versioning

    This approach allows us to:

    • Track API maturity and stability at a granular level
    • Support multiple versions simultaneously when needed
    • Provide clear deprecation and sunset timelines
    • Maintain backward compatibility during transitions

    Versioning Approach

    Current Strategy: Metadata-Based Versioning

    Each API endpoint includes version metadata in its route handler:

    /**
     * User Management API
     *
     * @version 1.2.0
     * @lastModified 2025-12-13
     * @stability production
     * @author Petunia Team
     */
    

    Version Format

    We use Semantic Versioning (SemVer) for API endpoints:

    • Major version (X.0.0): Breaking changes, incompatible API changes
    • Minor version (0.X.0): New features, backward-compatible additions
    • Patch version (0.0.X): Bug fixes, backward-compatible fixes

    Stability Levels

    Each API endpoint declares its stability:

    StabilityDescriptionGuarantees
    experimentalEarly development, API may change frequentlyNo backward compatibility guarantees
    unstableFeature complete but may have breaking changesLimited backward compatibility
    stableProduction-ready, follows deprecation policyFull backward compatibility for 12 months
    productionBattle-tested, widely usedFull backward compatibility, 18-month deprecation window
    deprecatedMarked for removal, use alternativeMinimum 6 months before sunset

    Version Metadata

    Route Handler Metadata

    Every API route should include comprehensive metadata:

    /**
     * [API Name] - [Brief Description]
     *
     * @version 2.1.0
     * @lastModified 2025-12-13
     * @author Petunia Team
     * @stability production
     *
     * @description
     *   Detailed description of what this API does, including:
     *   - Primary use cases
     *   - Key features
     *   - Performance characteristics
     *
     * @changelog
     *   - 2.1.0 (2025-12-13): Added support for cursor-based pagination
     *   - 2.0.0 (2025-11-01): BREAKING - Changed response format to standardized ApiResponse
     *   - 1.5.0 (2025-09-15): Added filtering by date range
     *   - 1.0.0 (2025-06-01): Initial stable release
     *
     * @deprecated false
     * @deprecationDate null
     * @sunsetDate null
     * @migrationPath null
     */
    

    Response Headers

    API responses include version information in headers:

    const response = NextResponse.json(data);
    
    // Version information
    response.headers.set('X-API-Version', '2.1.0');
    response.headers.set('X-API-Stability', 'production');
    
    // Optional: Deprecation warnings
    if (isDeprecated) {
      response.headers.set('X-API-Deprecated', 'true');
      response.headers.set('X-API-Sunset-Date', '2026-06-01');
      response.headers.set('X-API-Migration-Path', '/docs/api/migration/v2-to-v3');
    }
    
    // Request tracking
    response.headers.set('X-Request-Id', requestId);
    response.headers.set('X-Response-Time', `${duration}ms`);
    
    return response;
    

    OpenAPI Specification

    API versions are documented in /docs/openapi.yaml:

    openapi: 3.0.0
    info:
      title: Petunia API
      version: 1.0.0
      description: Comprehensive API documentation for the Petunia platform
    
    paths:
      /api/users:
        get:
          summary: List users
          x-stability: production
          x-version: 2.1.0
          x-deprecated: false
    

    Version Lifecycle

    Lifecycle Stages

    experimental → unstable → stable → production → deprecated → sunset
        ↓            ↓         ↓          ↓           ↓           ↓
      weeks      months    6+ months  12+ months  6-18 months  removed
    

    Transition Timeline

    TransitionMinimum DurationRequirements
    experimental → unstable2 weeksBasic functionality complete, initial testing done
    unstable → stable1 monthFull feature set, integration tests, documentation
    stable → production3 monthsProduction usage, performance validated, zero critical bugs
    production → deprecatedN/ANew version available, migration guide published
    deprecated → sunset6-18 monthsAll clients notified, usage < 5% of traffic

    Breaking Change Policy

    Breaking changes require a new major version:

    • Removing or renaming fields in responses
    • Changing field types (e.g., string → number)
    • Changing HTTP status codes for existing scenarios
    • Requiring new required parameters
    • Removing endpoints

    Non-breaking changes (minor/patch version):

    • Adding new optional parameters
    • Adding new fields to responses
    • Adding new endpoints
    • Fixing bugs that align with documented behavior
    • Performance improvements

    Adding New API Versions

    When to Create a New Version

    Create a new major version when you need to:

    1. Make breaking changes to an existing production API
    2. Refactor core data models that affect response structure
    3. Change authentication/authorization mechanisms
    4. Redesign API architecture (e.g., REST to GraphQL)

    Implementation Approaches

    Approach 1: Parallel Routes (Recommended)

    For major breaking changes, create parallel route structures:

    /app/api/
    ├── users/           # v1 (current production)
    │   ├── route.ts     # @version 1.5.0
    │   └── [id]/
    │       └── route.ts
    ├── v2/
    │   └── users/       # v2 (new version)
    │       ├── route.ts # @version 2.0.0
    │       └── [id]/
    │           └── route.ts
    

    Example:

    // /app/api/v2/users/route.ts
    /**
     * User Management API - Version 2
     *
     * @version 2.0.0
     * @stability stable
     * @changelog
     *   - 2.0.0 (2025-12-01): Complete rewrite with new response format
     *
     * @migrationFrom /api/users (v1)
     * @migrationGuide /docs/api/migration/users-v1-to-v2
     */
    
    export async function GET(request: NextRequest) {
      // New implementation with breaking changes
      const users = await fetchUsers();
    
      return NextResponse.json({
        data: users,
        meta: {
          version: '2.0.0',
          requestId: generateRequestId(),
          timestamp: new Date().toISOString()
        }
      });
    }
    

    Approach 2: Header-Based Versioning (Future Enhancement)

    For fine-grained versioning without URL changes:

    // Middleware to parse Accept-Version header
    export async function GET(request: NextRequest) {
      const requestedVersion = request.headers.get('Accept-Version') || '1.0';
    
      if (requestedVersion.startsWith('2.')) {
        return handleV2Request(request);
      } else {
        return handleV1Request(request);
      }
    }
    

    Client request:

    curl https://app.petunia.gardenpatch.xyz/api/users \
      -H "Accept-Version: 2.0" \
      -H "Authorization: Bearer token"
    

    Approach 3: In-Place Evolution (Minor Changes)

    For backward-compatible changes, evolve the existing route:

    /**
     * @version 1.6.0 (was 1.5.0)
     * @changelog
     *   - 1.6.0 (2025-12-13): Added optional 'include' parameter
     */
    
    export async function GET(request: NextRequest) {
      const { searchParams } = new URL(request.url);
      const include = searchParams.get('include')?.split(',') || [];
    
      // Backward compatible: new parameter is optional
      const users = await fetchUsers({ include });
    
      const response = NextResponse.json({ data: users });
      response.headers.set('X-API-Version', '1.6.0');
      return response;
    }
    

    Version Migration Checklist

    When creating a new major version:

    • Create migration guide documentation
    • Update OpenAPI specification
    • Add deprecation headers to old version
    • Set sunset date (minimum 6 months out)
    • Notify API consumers via email
    • Add migration path to response headers
    • Update client SDKs/libraries
    • Monitor usage of old version
    • Create automated migration tools if possible
    • Update API documentation site

    Client Migration Guide

    Discovering API Versions

    Check Response Headers

    All API responses include version information:

    curl -I https://app.petunia.gardenpatch.xyz/api/users
    
    HTTP/1.1 200 OK
    X-API-Version: 1.5.0
    X-API-Stability: production
    X-Request-Id: req_abc123
    

    Check for Deprecation Warnings

    Deprecated endpoints include warning headers:

    HTTP/1.1 200 OK
    X-API-Version: 1.5.0
    X-API-Deprecated: true
    X-API-Sunset-Date: 2026-06-01
    X-API-Migration-Path: /docs/api/migration/users-v1-to-v2
    Sunset: Sat, 01 Jun 2026 00:00:00 GMT
    

    Migration Process

    Step 1: Review Migration Guide

    When you receive a deprecation notice, review the migration guide:

    /docs/api/migration/[endpoint]-v[old]-to-v[new]
    

    Example: /docs/api/migration/users-v1-to-v2.md

    Step 2: Test Against New Version

    Use staging/sandbox environment to test new version:

    # Old version (deprecated)
    curl https://app.petunia.gardenpatch.xyz/api/users
    
    # New version (recommended)
    curl https://app.petunia.gardenpatch.xyz/api/v2/users
    

    Step 3: Update Client Code

    Update your application to use the new endpoint:

    // Before (v1)
    const response = await fetch('/api/users');
    const users = await response.json();
    
    // After (v2)
    const response = await fetch('/api/v2/users');
    const { data, meta } = await response.json();
    const users = data;
    

    Step 4: Deploy and Monitor

    Deploy your changes and monitor for errors:

    • Check error rates in your application
    • Verify response format matches expectations
    • Test edge cases and error scenarios
    • Monitor performance metrics

    Step 5: Verify Migration

    Confirm you're no longer calling deprecated endpoints:

    # Check response headers
    curl -I https://app.petunia.gardenpatch.xyz/api/v2/users
    
    HTTP/1.1 200 OK
    X-API-Version: 2.0.0
    X-API-Stability: production
    X-API-Deprecated: false
    

    Handling Breaking Changes

    Response Format Changes

    v1 Format:

    {
      "users": [...],
      "total": 100
    }
    

    v2 Format:

    {
      "data": [...],
      "meta": {
        "pagination": {
          "total": 100,
          "page": 1,
          "limit": 20
        }
      }
    }
    

    Migration Strategy:

    function normalizeResponse(version: string, response: any) {
      if (version.startsWith('1.')) {
        return {
          data: response.users,
          meta: { pagination: { total: response.total } }
        };
      }
      return response;
    }
    

    Field Renames

    v1:

    {
      "id": "user_123",
      "username": "john_doe",
      "created": "2025-01-01"
    }
    

    v2:

    {
      "id": "user_123",
      "handle": "john_doe",
      "createdAt": "2025-01-01T00:00:00Z"
    }
    

    Migration:

    interface UserV1 {
      username: string;
      created: string;
    }
    
    interface UserV2 {
      handle: string;
      createdAt: string;
    }
    
    function migrateUser(v1User: UserV1): UserV2 {
      return {
        handle: v1User.username,
        createdAt: new Date(v1User.created).toISOString()
      };
    }
    

    Deprecation Process

    Timeline

    Announcement → Deprecation → Sunset → Removal
         ↓             ↓            ↓         ↓
      3 months     6-18 months   shutdown   cleanup
    

    Announcement Phase (3 months before deprecation)

    Actions:

    • Publish deprecation notice in documentation
    • Send email to API consumers
    • Add deprecation notice to API changelog
    • Create migration guide
    • Update SDK documentation

    Communication:

    ## Deprecation Notice: /api/users (v1)
    
    **Effective Date**: 2026-01-01
    **Sunset Date**: 2026-06-01
    **Replacement**: /api/v2/users
    
    We are deprecating version 1 of the Users API. Please migrate to v2
    by June 1, 2026. See migration guide for details.
    

    Deprecation Phase (6-18 months)

    Actions:

    • Add deprecation headers to all responses
    • Log deprecation warnings in server logs
    • Monitor usage metrics
    • Provide migration assistance
    • Send periodic reminder emails

    Response Headers:

    response.headers.set('X-API-Deprecated', 'true');
    response.headers.set('X-API-Sunset-Date', '2026-06-01');
    response.headers.set('Sunset', 'Sat, 01 Jun 2026 00:00:00 GMT'); // RFC 8594
    response.headers.set('X-API-Migration-Path', '/docs/api/migration/users-v1-to-v2');
    response.headers.set('Link', '</api/v2/users>; rel="successor-version"');
    

    Logging:

    if (isDeprecatedEndpoint) {
      logger.warn('Deprecated API endpoint accessed', {
        endpoint: request.url,
        version: '1.5.0',
        sunsetDate: '2026-06-01',
        clientId: getClientId(request),
        userAgent: request.headers.get('user-agent')
      });
    }
    

    Sunset Phase (removal date)

    Actions:

    • Stop accepting new requests to deprecated endpoint
    • Return HTTP 410 Gone status
    • Provide clear error message with migration path
    • Monitor for stragglers
    • Offer emergency migration support

    Sunset Response:

    export async function GET(request: NextRequest) {
      return NextResponse.json(
        {
          error: {
            code: 'API_SUNSET',
            message: 'This API version has been sunset. Please migrate to v2.',
            details: {
              sunsetDate: '2026-06-01',
              replacementEndpoint: '/api/v2/users',
              migrationGuide: '/docs/api/migration/users-v1-to-v2'
            }
          }
        },
        {
          status: 410, // Gone
          headers: {
            'X-API-Deprecated': 'true',
            'X-API-Sunset': 'true',
            'X-API-Migration-Path': '/docs/api/migration/users-v1-to-v2',
            'Link': '</api/v2/users>; rel="successor-version"'
          }
        }
      );
    }
    

    Removal Phase (cleanup)

    Actions:

    • Remove route handler files
    • Clean up related code and tests
    • Archive migration documentation
    • Update OpenAPI specification
    • Send final communication to clients

    Examples

    Example 1: Stable Production Endpoint

    // /app/api/leads/route.ts
    /**
     * Lead Management API
     *
     * @version 3.2.1
     * @lastModified 2025-12-10
     * @stability production
     * @author Petunia Team
     *
     * @changelog
     *   - 3.2.1 (2025-12-10): Fix pagination cursor encoding issue
     *   - 3.2.0 (2025-11-15): Add support for custom field filtering
     *   - 3.1.0 (2025-10-01): Add bulk operations endpoint
     *   - 3.0.0 (2025-06-01): Standardized response format (BREAKING)
     */
    
    import { NextRequest, NextResponse } from 'next/server';
    import { withAuth } from '@/lib/auth/withAuth';
    import { apiSuccess, apiError } from '@/lib/utils/api-response';
    
    export const GET = withAuth(async (request: NextRequest) => {
      const startTime = Date.now();
      const requestId = `req_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
    
      try {
        const { searchParams } = new URL(request.url);
        const page = parseInt(searchParams.get('page') || '1');
        const limit = parseInt(searchParams.get('limit') || '20');
    
        const leads = await fetchLeads({ page, limit });
    
        const response = NextResponse.json({
          data: leads.data,
          meta: {
            requestId,
            timestamp: new Date().toISOString(),
            pagination: {
              total: leads.total,
              page,
              limit,
              hasMore: page * limit < leads.total
            }
          }
        });
    
        // Version headers
        response.headers.set('X-API-Version', '3.2.1');
        response.headers.set('X-API-Stability', 'production');
        response.headers.set('X-Request-Id', requestId);
        response.headers.set('X-Response-Time', `${Date.now() - startTime}ms`);
    
        return response;
      } catch (error) {
        return apiError('Failed to fetch leads', { requestId, error });
      }
    });
    

    Example 2: Deprecated Endpoint

    // /app/api/contacts/route.ts
    /**
     * Contact Management API - DEPRECATED
     *
     * @version 1.5.0
     * @stability deprecated
     * @deprecated true
     * @deprecationDate 2025-12-01
     * @sunsetDate 2026-06-01
     * @migrationPath /docs/api/migration/contacts-to-leads
     * @successorEndpoint /api/v2/leads
     *
     * @changelog
     *   - 1.5.0 (2025-12-01): DEPRECATED - Migrate to /api/v2/leads
     *   - 1.4.0 (2025-09-01): Added email validation
     */
    
    import { NextRequest, NextResponse } from 'next/server';
    import { createLogger } from '@/lib/utils/logging';
    
    const logger = createLogger('contacts-api-deprecated');
    
    export async function GET(request: NextRequest) {
      // Log deprecated API usage
      logger.warn('Deprecated API accessed', {
        endpoint: '/api/contacts',
        version: '1.5.0',
        sunsetDate: '2026-06-01',
        clientIP: request.headers.get('x-forwarded-for'),
        userAgent: request.headers.get('user-agent')
      });
    
      // Still process the request during deprecation period
      const contacts = await fetchContacts();
    
      const response = NextResponse.json({
        data: contacts,
        deprecationNotice: {
          deprecated: true,
          sunsetDate: '2026-06-01',
          message: 'This endpoint is deprecated. Please migrate to /api/v2/leads',
          migrationGuide: '/docs/api/migration/contacts-to-leads'
        }
      });
    
      // Deprecation headers
      response.headers.set('X-API-Version', '1.5.0');
      response.headers.set('X-API-Stability', 'deprecated');
      response.headers.set('X-API-Deprecated', 'true');
      response.headers.set('X-API-Sunset-Date', '2026-06-01');
      response.headers.set('Sunset', 'Sat, 01 Jun 2026 00:00:00 GMT');
      response.headers.set('X-API-Migration-Path', '/docs/api/migration/contacts-to-leads');
      response.headers.set('Link', '</api/v2/leads>; rel="successor-version"');
    
      // Warning header (RFC 7234)
      response.headers.set('Warning', '299 - "This API version is deprecated and will be sunset on 2026-06-01"');
    
      return response;
    }
    

    Example 3: Experimental Feature

    // /app/api/insights/contextual/route.ts
    /**
     * Contextual AI Insights - EXPERIMENTAL
     *
     * @version 0.2.0
     * @stability experimental
     * @lastModified 2025-12-13
     *
     * @description
     *   EXPERIMENTAL: This API is under active development and may change
     *   without notice. Do not use in production applications.
     *
     * @changelog
     *   - 0.2.0 (2025-12-13): Added sentiment analysis
     *   - 0.1.0 (2025-12-01): Initial experimental release
     */
    
    export async function POST(request: NextRequest) {
      const response = NextResponse.json({
        data: insights,
        warning: 'EXPERIMENTAL: This API may change without notice'
      });
    
      response.headers.set('X-API-Version', '0.2.0');
      response.headers.set('X-API-Stability', 'experimental');
      response.headers.set('X-Feature-Flag', 'contextual-insights');
    
      return response;
    }
    

    Example 4: Version-Specific Response Formats

    // /app/api/users/route.ts
    /**
     * User Management API - Multi-version support
     *
     * @version 2.0.0
     * @stability production
     */
    
    export async function GET(request: NextRequest) {
      const acceptVersion = request.headers.get('Accept-Version') || '2.0';
      const users = await fetchUsers();
    
      // v1 format (deprecated)
      if (acceptVersion.startsWith('1.')) {
        return NextResponse.json({
          users: users.map(u => ({
            id: u.id,
            name: u.name,
            email: u.email,
            created: u.createdAt
          })),
          total: users.length
        }, {
          headers: {
            'X-API-Version': '1.0.0',
            'X-API-Deprecated': 'true',
            'X-API-Sunset-Date': '2026-06-01'
          }
        });
      }
    
      // v2 format (current)
      return NextResponse.json({
        data: users,
        meta: {
          version: '2.0.0',
          pagination: {
            total: users.length,
            page: 1,
            limit: 20
          }
        }
      }, {
        headers: {
          'X-API-Version': '2.0.0',
          'X-API-Stability': 'production'
        }
      });
    }
    

    Best Practices

    For API Developers

    1. Always include version metadata in route handlers
    2. Use semantic versioning for version numbers
    3. Document breaking changes in changelog
    4. Provide migration guides for major version changes
    5. Monitor deprecated endpoint usage before sunset
    6. Set realistic sunset timelines (minimum 6 months)
    7. Communicate early and often with API consumers
    8. Test backward compatibility thoroughly
    9. Version response formats consistently
    10. Use stability markers to set expectations

    For API Consumers

    1. Monitor response headers for deprecation notices
    2. Subscribe to API changelog notifications
    3. Test against new versions in sandbox before production
    4. Implement version negotiation in clients
    5. Handle deprecation warnings gracefully
    6. Plan migrations early (don't wait until sunset)
    7. Cache version information appropriately
    8. Log API errors with version context
    9. Use request IDs for debugging
    10. Follow migration guides carefully

    Versioning Anti-Patterns

    Don't:

    • ❌ Make breaking changes without version bump
    • ❌ Sunset APIs without migration path
    • ❌ Use version numbers inconsistently
    • ❌ Remove deprecated endpoints immediately
    • ❌ Skip migration documentation
    • ❌ Ignore deprecation warnings
    • ❌ Version every minor change
    • ❌ Keep too many versions active simultaneously
    • ❌ Change versioning strategy mid-project
    • ❌ Forget to update OpenAPI spec

    Do:

    • ✅ Plan breaking changes carefully
    • ✅ Provide clear migration paths
    • ✅ Use semantic versioning consistently
    • ✅ Give adequate deprecation notice (6+ months)
    • ✅ Document all changes thoroughly
    • ✅ Monitor and respond to deprecation warnings
    • ✅ Version only when necessary
    • ✅ Maintain 1-2 active versions maximum
    • ✅ Stick to versioning strategy
    • ✅ Keep documentation synchronized

    Future Enhancements

    Planned Improvements

    1. Automated Version Detection Middleware

      • Centralized version header injection
      • Automatic deprecation warning enforcement
      • Usage analytics by version
    2. GraphQL Versioning

      • Schema versioning for GraphQL endpoints
      • Deprecated field tracking
      • Migration tooling
    3. SDK Auto-Generation

      • TypeScript SDK from OpenAPI spec
      • Version-aware client libraries
      • Automatic migration scripts
    4. Version Analytics Dashboard

      • Track version adoption rates
      • Monitor deprecated endpoint usage
      • Forecast sunset readiness
    5. Content Negotiation

      • Accept-Version header support
      • Automatic version routing
      • Response format negotiation

    Related Documentation

    • ARCHITECTURE.md - System architecture overview
    • ARCHITECTURE_PLAN.md - Migration plan (see P3-4)
    • openapi.yaml - OpenAPI specification
    • GIT_FLOW.md - Version control workflow
    • PRE_DEPLOYMENT_CHECKLIST.md - Deployment process

    Support

    For questions about API versioning:

    • Email: support@gardenpatch.xyz
    • Documentation: https://docs.petunia.gardenpatch.xyz/api/versioning
    • Changelog: https://petunia.gardenpatch.xyz/changelog

    Maintained by: Petunia Platform Team Review Cycle: Quarterly Next Review: 2026-03-13

    On this page
    Table of ContentsOverviewVersioning ApproachCurrent Strategy: Metadata-Based VersioningVersion MetadataRoute Handler MetadataResponse HeadersOpenAPI SpecificationVersion LifecycleLifecycle StagesTransition TimelineBreaking Change PolicyAdding New API VersionsWhen to Create a New VersionImplementation ApproachesVersion Migration ChecklistClient Migration GuideDiscovering API VersionsMigration ProcessHandling Breaking ChangesDeprecation ProcessTimelineAnnouncement Phase (3 months before deprecation)Deprecation Notice: /api/users (v1)Deprecation Phase (6-18 months)Sunset Phase (removal date)Removal Phase (cleanup)ExamplesExample 1: Stable Production EndpointExample 2: Deprecated EndpointExample 3: Experimental FeatureExample 4: Version-Specific Response Formats