How the FreeLLMAPI Model Catalog Sync Works: Signed Catalog Synchronization Explained

FreeLLMAPI synchronizes its local model catalog with an upstream signed catalog service through a cryptographically verified process that runs on a scheduled interval and supports offline re-application of cached catalogs.

The FreeLLMAPI model catalog sync is a security-critical background service that keeps your local deployment aligned with the latest available AI models. Located in server/src/services/catalog-sync.ts, this system fetches, verifies, and applies model definitions while preserving user customizations and ensuring zero-trust integrity through Ed25519 signatures.

Scheduler Initialization and Boot Sequence

When the FreeLLMAPI server starts, startCatalogSync() establishes the synchronization lifecycle.

The function performs three critical setup tasks:

  • Registers a one-off timer (BOOT_DELAY_MS) for the initial sync after startup
  • Schedules a recurring interval (SYNC_INTERVAL_MS, approximately twice daily)
  • Immediately calls reapplyCachedCatalog() to restore the last verified catalog from the local SQLite settings table

This dual-timer approach ensures rapid availability of models after boot while maintaining freshness through periodic updates.

// Start the background sync (usually called from server initialization)
import { startCatalogSync } from './services/catalog-sync.js';
import { scheduler } from '../lib/scheduler.js';

startCatalogSync(scheduler);

Source: server/src/services/catalog-sync.ts lines 33-45

Fetching the Catalog with Incremental Updates

The syncCatalog() function constructs authenticated requests to <base-url>/v1/latest with intelligent delta handling.

Request construction follows these rules:

  • Premium authentication: When a license key exists, adds Authorization: Bearer <key> header
  • Incremental fetch: Appends ?since=<applied_version> when a version is already applied (unless force=true)
  • Fresh fetch: Bypasses the since parameter when forcing a full refresh
// Manually trigger a sync, e.g. after a user upgrades their license
import { syncCatalog } from './services/catalog-sync.js';

const result = await syncCatalog(true); // `force=true` ignores the `since` shortcut
console.log(result); 
// {ok: true, action: 'applied', version: '2026.09.01', ...}

The since parameter enables bandwidth-efficient synchronization by allowing the server to return only changed portions of the catalog when the version hasn't advanced.

Source: lines 71-84

Cryptographic Signature Verification

Before any catalog data is processed, FreeLLMAPI enforces strict signature validation to prevent supply-chain attacks.

The verification flow in syncCatalog():

  1. Extracts the x-catalog-signature header from the HTTP response
  2. Reads the response body as raw bytes
  3. Verifies the signature against the pinned Ed25519 public key (PINNED_CATALOG_PUBKEY) embedded in the binary

If verification fails, the entire response is discarded and the sync aborts. This signature-first security model ensures that even a compromised CDN cannot inject malicious model definitions, as the client only trusts content signed by the matching private key held by the upstream service.

Source: lines 94-99

Payload Validation and Schema Checking

After signature verification, the JSON payload undergoes strict validation through isCatalog().

The validator checks required structural fields:

  • version — catalog version string
  • tier — deployment tier identifier
  • models — array of chat model definitions
  • quirks — model behavior overrides
  • Optional arrays: embeddings, videoModels, mediaModels, transcriptionModels

Type checking ensures each field conforms to expected shapes before the sync proceeds. This prevents partially corrupted or malformed catalogs from affecting the database state.

Source: lines 100-150

Version Safety and Migration Protection

The FreeLLMAPI model catalog sync includes a safeguard against destructive rollbacks.

Before applying any catalog, the system compares catalog.version against MIN_CATALOG_VERSION — a hard-coded constant representing the bundled migration baseline. If the fetched catalog version is older than this minimum, the sync is skipped entirely.

This protection ensures that:

  • Downgrade attacks via stale catalog delivery are blocked
  • Database migrations always move forward
  • Offline re-application of cached catalogs never regresses schema state

Source: lines 104-109

Atomic Catalog Application

When version or tier changes are detected, applyCatalog() executes within a single SQLite transaction to maintain consistency.

The application process handles multiple model categories:

Model Type Target Table Special Handling
Chat models models Respects user-owned rows, applies overrides
Image/audio media_models Gated by MEDIA_PLATFORMS allow-list
Video videoModels Gated by VIDEO_PLATFORMS allow-list
Transcription transcriptionModels Gated by TRANSCRIPTION_PLATFORMS allow-list
Embeddings embeddings Optional snapshot section

Key application behaviors:

  • User row protection: Rows with source='user' are preserved and never overwritten or deleted
  • Tombstone awareness: Checks catalog_model_tombstones for permanently retired models
  • Override handling: Applies model_config_overrides and fallback_config rows
  • Profile consistency: Maintains relationships between user profiles and available models
  • Stale row cleanup: Deletes catalog-managed rows (source='catalog') that no longer appear in the new snapshot
  • Quirk replacement: Clears existing quirks and inserts the complete new set wholesale

Source: lines 57-66, 75-129, 140-250, 260-470

State Persistence and Caching

After successful application, the sync state is persisted to the settings table:

  • catalog_applied_version — the applied catalog version
  • catalog_applied_tier — the deployment tier
  • catalog_applied_json — complete raw catalog JSON for offline use

Additional metadata is recorded:

  • lastSyncMs — timestamp of the sync attempt
  • lastError — error message if the sync failed

This caching enables the offline re-application capability that makes FreeLLMAPI resilient to network outages.

Source: lines 114-130

License Status Refresh

Independently of catalog synchronization, refreshLicenseStatus() maintains premium entitlement state.

This function:

  • Contacts /v1/license/check when a license key is configured
  • Updates cached license status in the database
  • Logs failures without aborting the catalog sync

The separation of concerns allows model availability to proceed even when license verification is temporarily unavailable.

Source: lines 44-63

Offline Re-Application via Cached Catalogs

The reapplyCachedCatalog() function provides deterministic recovery for server restarts.

Execution flow:

  1. Reads catalog_applied_json from the settings table
  2. Re-validates the cached payload with isCatalog()
  3. Executes applyCatalog() without any network traffic

This guarantees that the local database reflects the last known-good catalog state even when the server boots without internet connectivity. The re-validation step ensures data integrity against disk corruption or manual tampering.

Source: lines 95-108

Querying Sync State

The getSyncState() function exposes current synchronization status for monitoring and UI purposes.

// Query the current sync state (useful for UI)
import { getSyncState } from './services/catalog-sync.js';

const state = getSyncState();
console.log(state);
/*
{
  baseUrl: 'https://api.freellmapi.co',
  appliedVersion: '2026.09.01',
  appliedTier: 'live',
  lastSyncMs: 1725112000000,
  lastError: ''
}
*/

This enables dashboards to display synchronization health, applied catalog versions, and error conditions to administrators.

Key Architectural Files

File Role
server/src/services/catalog-sync.ts Core implementation: fetching, verifying, applying, and caching
server/src/services/model-state.ts Tombstone handling, overrides, and retired model reinstatement
server/src/services/media.ts Platform allow-lists (MEDIA_PLATFORMS, VIDEO_PLATFORMS, TRANSCRIPTION_PLATFORMS)
server/src/db/index.js SQLite helpers (getDb, getSetting, setSetting)
shared/types.ts Shared type definitions including Platform

Summary

  • FreeLLMAPI model catalog sync is driven by catalog-sync.ts with scheduled and on-demand execution modes
  • Ed25519 signature verification provides zero-trust integrity before any data is processed
  • Incremental updates via the since parameter reduce bandwidth; force=true enables full refresh
  • Migration protection via MIN_CATALOG_VERSION prevents destructive catalog rollbacks
  • Atomic SQLite transactions ensure consistent application across chat, media, video, transcription, and embedding models
  • Source-of-truth handling preserves user-owned rows and respects tombstones
  • Offline resilience through cached catalog re-application on every boot

Frequently Asked Questions

How often does FreeLLMAPI sync the model catalog?

The sync runs approximately twice daily via SYNC_INTERVAL_MS, plus an immediate attempt after BOOT_DELAY_MS on server startup. Administrators can trigger manual syncs with syncCatalog(true) at any time.

What happens if the catalog signature verification fails?

The entire response is discarded immediately. No database changes occur, and the error is recorded in lastError. The system continues operating with the previously applied (or re-applied cached) catalog until a valid signed response is received.

Can FreeLLMAPI work without internet connectivity?

Yes. On every boot, reapplyCachedCatalog() validates and re-applies the last known-good catalog from local SQLite storage without network access. Models that were available before disconnection remain functional.

How does FreeLLMAPI handle user-customized model configurations?

User-owned rows (source='user') are preserved across all syncs. They take precedence over catalog definitions on collision and are never deleted by the synchronization process. The catalog_model_tombstones table separately tracks permanently retired upstream models.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →