← Back to Blog

Version-Locked Entitlements: Why Breaking Changes Don’t Break Your Consumers

When an API provider ships v2.0, what happens to consumers still running v1.0?

In most systems, the answer is: they break, or they scramble to upgrade. Hexarch’s version-locking architecture ensures a different outcome: nothing happens until the consumer explicitly chooses to upgrade.

The Data Model

The architecture starts with two TypeScript interfaces that define the contract:

interface AccessPlan {
  id: string;
  apiVersionId: string;  // Bound to a specific version
  name: string;
  description: string;
  state: LifecycleState;
  quota: { value: number; unit: 'Requests' | 'Bytes'; period: 'Second' | 'Minute' | 'Hour' | 'Day' | 'Month' };
  rateLimit: { requestsPerSecond: number; burst: number };
  policies: Policy[];
  approvalRequired: boolean;
  billingModel: 'Free' | 'Usage-Based' | 'Subscription';
  termsOfService?: string;
}

interface ApiVersion {
  id: string;
  version: string;
  state: LifecycleState;
  plans: AccessPlan[];
  policies: Policy[];
  createdAt: string;
  updatedAt?: string;
  effectiveAt?: string;
  deprecatedAt?: string;
  retirementAt?: string;
  history: LifecycleHistoryEntry[];
}

The key relationship: AccessPlan.apiVersionId creates a permanent binding. When a consumer subscribes to a plan, they’re subscribing to that specific version—not to the API in general.

The Subscription Contract

When an application subscribes, the system records:

interface Subscription {
  id: string;
  appId: string;
  appName: string;
  apiId: string;
  apiVersionId: string;  // Locked to this version
  planId: string;
  status: SubscriptionStatus;
  subscribedAt: string;
  gatewayAcknowledge?: boolean;  // Gateway has received the lock
}

The gatewayAcknowledge field is a propagation indicator in the UI model. In the current dashboard demo, new subscriptions start with gatewayAcknowledge: false, and sample data may include a subscription where it is already true.

How the Gateway Enforces It

The GatewayNode interface tracks what’s actually running:

interface GatewayNode {
  id: string;
  appliedSnapshotId: string;
  desiredSnapshotId: string;
  lastSyncError?: string;
}

When a subscription is created in the Developer Portal demo, the plan controls approval state immediately: if the plan requires approval, the subscription status starts as Pending Approval; otherwise it starts as Active.

Hexarch’s production intent is that version locks are enforced at the gateway boundary. In the current UI code, gatewayAcknowledge represents that concept, but the demo does not implement an automatic backend reconciliation loop that flips it from false to true.

The Developer Portal Implementation

In the DeveloperPortal.tsx component, consumers interact with this system through a VersionSubscriptionCard:

  • Browse available API versions and their states (Published, Deprecated, Retired)
  • Select a plan tier (Free, Business, Enterprise)
  • Confirm the version lock before subscribing
  • Track propagation status until gatewayAcknowledge confirms

The UI makes the lock explicit: “You are subscribing to v1.0. This subscription will not automatically upgrade to v2.0.”

Why This Architecture Matters

For API Consumers:

  • No surprise breaking changes
  • Upgrade on your timeline, not the provider’s
  • Clear lifecycle visibility (deprecation dates, retirement warnings)

For API Providers:

  • Ship new versions without coordinating with every consumer
  • Deprecate old versions with defined sunset periods
  • Enforce quota and rate limits per version tier

For Compliance:

  • Audit trail shows exactly which version each consumer was using at any point in time
  • Version locks are immutable—once set, they don’t change silently
  • Gateway acknowledgment proves the lock was enforced, not just configured

The Lifecycle State Machine

Versions follow a defined lifecycle:

enum LifecycleState {
  DRAFT = 'Draft',
  PUBLISHED = 'Published',
  DEPRECATED = 'Deprecated',
  RETIRED = 'Retired'
}

Transitions are recorded in the history array on each ApiVersion. Consumers on a deprecated version see warnings in the portal. A retired version is a hard stop in the lifecycle model; in the current dashboard demo, it’s represented as state + UI messaging rather than an enforced traffic router.

Try It

The Developer Portal is available at /portal. Browse the API catalog, select a version, and subscribe. Watch the propagation status as the lock flows from control plane to gateway fleet.

In the demo, subscriptions activate based on approval rules; gatewayAcknowledge is displayed as the propagation concept. That’s the difference between “we recorded your subscription” and “your subscription is enforced”—and the UI keeps those ideas separate.