# FreeLLMAPI Model Catalog Sync Mechanism: How It Fetches, Verifies, and Applies Updates

> Discover how FreeLLMAPI's model catalog sync mechanism fetches, verifies, and applies updates using cryptographically signed remote catalogs and atomic updates for reliable offline model management.

- Repository: [Tashfeen/freellmapi](https://github.com/tashfeenahmed/freellmapi)
- Tags: internals
- Published: 2026-06-22

---

**FreeLLMAPI synchronizes its local SQLite database with a cryptographically signed remote catalog every 12 hours, verifying Ed25519 signatures, gating updates by minimum version, and applying changes atomically while preserving user-disabled model states and caching verified catalogs for offline resilience.**

FreeLLMAPI maintains an up-to-date model catalog through a robust synchronization mechanism implemented in [`server/src/services/catalog-sync.ts`](https://github.com/tashfeenahmed/freellmapi/blob/main/server/src/services/catalog-sync.ts). This system ensures that self-hosted instances receive the latest model definitions, capability quirks, and pricing tiers without manual intervention. The mechanism combines cryptographic verification, conditional HTTP requests, and atomic database transactions to safely update the local catalog while maintaining zero-downtime operation.

## Bootstrap and Periodic Polling

The sync lifecycle begins when `startCatalogSync()` is invoked at server startup ([source lines 81‑87](https://github.com/tashfeenahmed/freellmapi/blob/main/server/src/services/catalog-sync.ts#L81-L87)). This function implements a two-phase initialization:

- **Boot delay**: A `BOOT_DELAY_MS` of 10 seconds allows the rest of the server to initialize before the first network call.
- **Recurring schedule**: After the initial delay, `syncCatalog()` executes immediately and then schedules itself to repeat every `SYNC_INTERVAL_MS` (12 hours) ([source lines 43‑44, 94‑95](https://github.com/tashfeenahmed/freellmapi/blob/main/server/src/services/catalog-sync.ts#L43-L44)).

Each execution also refreshes the license status, ensuring that premium tier changes are detected promptly.

## Fetching and Authenticating the Catalog

The `syncCatalog()` function constructs a request to `<base-url>/v1/latest` with tier-aware authentication:

- **Premium tier detection**: If a license key exists, the function adds an `Authorization: Bearer <key>` header, which causes the service to return the *live* tier catalog; otherwise, a monthly snapshot is served ([source lines 28‑31](https://github.com/tashfeenahmed/freellmapi/blob/main/server/src/services/catalog-sync.ts#L28-L31)).
- **Conditional requests**: When the server already knows the last applied version, it appends a `since` query parameter, allowing the server to return **304 Not Modified** if the catalog has not changed, saving bandwidth and processing time ([source lines 31‑33](https://github.com/tashfeenahmed/freellmapi/blob/main/server/src/services/catalog-sync.ts#L31-L33)).

## Cryptographic Verification and Version Gating

Before any update is applied, the mechanism performs strict security validation:

### Ed25519 Signature Verification

The HTTP response must include an `x-catalog-signature` header. The raw response body is verified against an Ed25519 public key that is hard-coded in the binary (or overridden via the `CATALOG_PUBKEY` environment variable) ([source lines 60‑63, 42‑45](https://github.com/tashfeenahmed/freellmapi/blob/main/server/src/services/catalog-sync.ts#L60-L63)). If verification fails, the entire update is discarded to prevent tampering.

### Minimum Version Enforcement

Even verified catalogs are rejected if their `version` field is older than `MIN_CATALOG_VERSION` (set to `2026.06.07` at the time of writing). This prevents stale monthly snapshots from rolling back database migrations that are baked into the binary ([source lines 39‑42, 52‑58](https://github.com/tashfeenahmed/freellmapi/blob/main/server/src/services/catalog-sync.ts#L39-L42)).

## Applying Updates Atomically

When a newer valid catalog is detected, `applyCatalog()` executes inside a single SQLite transaction to ensure consistency ([source lines 55‑56, 90‑91](https://github.com/tashfeenahmed/freellmapi/blob/main/server/src/services/catalog-sync.ts#L55-L56)). This process handles several distinct data types:

### Model Upserts and User Preferences

For each model entry in the catalog, the system either updates an existing row or inserts a new one. Importantly:
- **Catalog-disabled models**: If the catalog sets `enabled` to `false`, the model is disabled regardless of local state.
- **User-disabled models**: A model that was manually disabled locally remains disabled even if the catalog later re-enables it, preserving user autonomy ([source lines 44‑53](https://github.com/tashfeenahmed/freellmapi/blob/main/server/src/services/catalog-sync.ts#L44-L53)).

### Media Model Routing

Entries with a `modality` of `image` or `audio` are routed to a separate `media_models` table, while unknown platforms are counted and skipped to ensure forward compatibility ([source lines 18‑30, 95‑102](https://github.com/tashfeenahmed/freellmapi/blob/main/server/src/services/catalog-sync.ts#L18-L30)).

### Custom Provider Handling

Models belonging to a `custom` platform or to providers not compiled into the current binary are ignored. This allows the catalog to include bleeding-edge providers without breaking older server versions ([source lines 22‑27](https://github.com/tashfeenahmed/freellmapi/blob/main/server/src/services/catalog-sync.ts#L22-L27)).

### Cleanup and Quirks

The routine performs garbage collection on stale data:
- **Orphaned models**: Models that disappeared from the catalog are deleted, including their associated `fallback_config` rows ([source lines 68‑81, 84‑94](https://github.com/tashfeenahmed/freellmapi/blob/main/server/src/services/catalog-sync.ts#L68-L81)).
- **Quirks replacement**: All existing quirks are wiped and replaced wholesale with the catalog’s `quirks` array, ensuring behavior changes propagate exactly as specified ([source lines 96‑110](https://github.com/tashfeenahmed/freellmapi/blob/main/server/src/services/catalog-sync.ts#L96-L110)).

The function returns a `counts` summary object detailing updated, inserted, and removed rows, skipped platforms, and quirks applied, which is logged for observability.

## Offline Resilience and State Management

FreeLLMAPI ensures continuity during network outages through aggressive caching:

### Cached Catalog Re-application

On every boot, `reapplyCachedCatalog()` reads the cached JSON from the `settings` table, validates it again, and re-applies it without a network call. This prevents database drift when the server restarts while offline ([source lines 58‑77](https://github.com/tashfeenahmed/freellmapi/blob/main/server/src/services/catalog-sync.ts#L58-L77)).

### Persistent State Tracking

After a successful apply, the service records:
- `catalog_applied_version`, `catalog_applied_tier`, and the raw verified JSON (`catalog_applied_json`) in the `settings` table ([source lines 62‑70](https://github.com/tashfeenahmed/freellmapi/blob/main/server/src/services/catalog-sync.ts#L62-L70)).
- `catalog_last_sync_ms` timestamp and clears any previous error messages.

### Error Handling

Any failure—whether HTTP errors, missing signatures, verification failures, or malformed payloads—is caught and stored in `catalog_last_error`. The sync returns `{ ok: false, action: 'error' }` to signal the failure without crashing the server ([source lines 84‑89](https://github.com/tashfeenahmed/freellmapi/blob/main/server/src/services/catalog-sync.ts#L84-L89)).

## Implementation Examples

**Start the background sync (typically invoked in the server entry point):**

```ts
import { startCatalogSync } from './server/src/services/catalog-sync.js';

// Begins the 10s boot-delay, then polls twice daily
startCatalogSync();

```

**Force a one-off catalog refresh (e.g., after premium key activation):**

```ts
import { syncCatalog } from './server/src/services/catalog-sync.js';

// Bypasses the `since` short-circuit to force a full fetch
await syncCatalog(/* force */ true);

```

**Manually re-apply the cached catalog (useful after database restoration):**

```ts
import { reapplyCachedCatalog } from './server/src/services/catalog-sync.js';

const result = reapplyCachedCatalog();
console.log('Re-apply outcome:', result);

```

**Inspect the current sync state:**

```ts
import { getSyncState } from './server/src/services/catalog-sync.js';

console.log(getSyncState());
/* {
   baseUrl: 'https://api.freellmapi.co',
   appliedVersion: '2026.06.07',
   appliedTier: 'monthly',
   lastSyncMs: 1687718400000,
   lastError: ''
} */

```

## Summary

- FreeLLMAPI pulls the model catalog from `<base-url>/v1/latest` every 12 hours via `startCatalogSync()` in [`server/src/services/catalog-sync.ts`](https://github.com/tashfeenahmed/freellmapi/blob/main/server/src/services/catalog-sync.ts).
- All updates require Ed25519 signature verification via the `x-catalog-signature` header and must satisfy the `MIN_CATALOG_VERSION` gate.
- Changes are applied atomically within a SQLite transaction, with user-disabled models preserved, media models routed to separate tables, and custom providers ignored.
- The verified catalog JSON is cached in the `settings` table, enabling `reapplyCachedCatalog()` to restore state during offline restarts.
- Comprehensive error handling stores failure messages in `catalog_last_error` without interrupting server operation.

## Frequently Asked Questions

### How does FreeLLMAPI handle updates when the server is offline?

FreeLLMAPI stores the last successfully verified catalog JSON in the `settings` table as `catalog_applied_json`. On every boot, `reapplyCachedCatalog()` validates and re-applies this cached version without making a network request, ensuring the database remains synchronized with the last known state even without internet connectivity.

### What prevents a malicious catalog from downgrading the system?

The sync mechanism implements version gating using `MIN_CATALOG_VERSION` (currently `2026.06.07`). Even if a catalog passes Ed25519 signature verification, it is rejected if its `version` field is older than this constant, preventing stale snapshots from rolling forward-compatible database migrations.

### How does the sync mechanism respect user preferences for disabled models?

During the atomic apply phase in `applyCatalog()`, the system checks local state before enabling models. If a user has manually disabled a model, that flag persists in the database even if the incoming catalog marks it as enabled, ensuring that user autonomy overrides remote configuration.

### What is the difference between live and monthly catalog tiers?

The tier depends on authentication: requests with a valid `Authorization: Bearer` header receive the *live* tier (updated continuously), while unauthenticated requests receive a *monthly* snapshot. This allows premium users to access immediate updates while free-tier instances receive stable, batched updates.