May 11, 2026

Never Break a Client: Architecting API Versioning in Laravel

By Paresh Prajapati • Lead Architect

Never Break a Client: Architecting API Versioning in Laravel

The Nightmare of the Breaking Change

When building a B2B SaaS platform at Smart Tech Devs, your API is a binding contract with your clients. Imagine a scenario where a client has integrated your API into their internal ERP system. One day, you decide to restructure the user payload, changing first_name and last_name into a single full_name field. You deploy the update, and instantly, your client's ERP integration crashes. Their workflows halt, and you lose their trust.

In enterprise software, you cannot force external clients (or even older versions of your own mobile app) to update their code the exact second you update your backend. You must support older data structures while continuing to innovate. The solution is API Versioning.

Architecting URL-Based Versioning

While there are several ways to version APIs (like using Accept headers), URL-based versioning (e.g., /api/v1/ and /api/v2/) is the most explicit, cache-friendly, and developer-friendly approach for B2B platforms.

Step 1: Route Segregation

In Laravel 11+, we architect our routing to clearly delineate between versions. Instead of stuffing everything into a single api.php file, we map specific files in our bootstrap/app.php or route service provider.


// routes/api_v1.php
use App\Http\Controllers\Api\V1\UserController;

Route::prefix('v1')->group(function () {
    Route::get('/users', [UserController::class, 'index']);
});

// routes/api_v2.php
use App\Http\Controllers\Api\V2\UserController;

Route::prefix('v2')->group(function () {
    Route::get('/users', [UserController::class, 'index']);
});

Step 2: Leveraging API Resources for Transformation

The biggest mistake developers make with versioning is duplicating their entire database logic and Eloquent models for every version. Do not duplicate business logic. The database remains the same; only the presentation of the data changes.

We handle this presentation layer strictly through Laravel API Resources.


// App\Http\Resources\V1\UserResource.php
namespace App\Http\Resources\V1;

use Illuminate\Http\Resources\Json\JsonResource;

class UserResource extends JsonResource
{
    public function toArray($request)
    {
        // V1 clients expect separate name fields
        return [
            'id' => $this->id,
            'first_name' => $this->first_name,
            'last_name' => $this->last_name,
            'email' => $this->email,
        ];
    }
}

// App\Http\Resources\V2\UserResource.php
namespace App\Http\Resources\V2;

use Illuminate\Http\Resources\Json\JsonResource;

class UserResource extends JsonResource
{
    public function toArray($request)
    {
        // V2 clients get the newly optimized, consolidated payload
        return [
            'id' => $this->id,
            'full_name' => $this->first_name . ' ' . $this->last_name,
            'email' => $this->email,
            'status' => $this->is_active ? 'active' : 'inactive', // New V2 feature
        ];
    }
}

Step 3: The Controller Layer

Your controllers now simply fetch the data using your standard Repositories or Services, and then pass that data to the version-specific Resource.


// App\Http\Controllers\Api\V2\UserController.php
namespace App\Http\Controllers\Api\V2;

use App\Http\Controllers\Controller;
use App\Models\User;
use App\Http\Resources\V2\UserResource;

class UserController extends Controller
{
    public function index()
    {
        // The query logic is identical to V1
        $users = User::active()->paginate(50);
        
        // But the transformation is strictly V2
        return UserResource::collection($users);
    }
}

Conclusion

API Versioning is not an afterthought; it is a fundamental requirement for durable B2B SaaS. By separating your routing and isolating payload transformations inside version-specific API Resources, you can continuously evolve your Laravel backend without ever breaking the integrations your clients rely on.

Paresh Prajapati
Lead Architect, Smart Tech Devs