Skip to content

Checking for Updates (Client-Side)

This guide shows you how to implement update checking in your application.

The Update Check Endpoint

Endpoint: GET /api/patcher/check

Query Parameters: - app_id (required): Your application's unique identifier - channel (optional): Which channel to check (default: production)

Example:

GET https://apis.novasuite.one/api/patcher/check?app_id=one.novasuite.myapp&channel=production

Response Format

Success (200):

{
  "id": "one.novasuite.myapp",
  "channel": "production",
  "latest": {
    "version": "1.2.0",
    "download_url": "https://serve.novasuite.one/downloads/nova-suite/one.novasuite.myapp/v1.2.0.zip",
    "notes": "Fixed critical bugs and improved performance",
    "hash": "a4b3c2d1e5f6...",
    "published_at": "2026-01-19T05:00:00.000Z",
    "channel": "production",
    "install_action": "unzip",
    "display_mode": "active",
    "update_action": "replace",
    "is_latest": true
  }
}

No Updates (404):

{
  "message": "No releases found for this channel."
}

Implementation Examples

JavaScript/Node.js

const CURRENT_VERSION = "1.1.0";
const APP_ID = "one.novasuite.myapp";
const CHANNEL = "production"; // or "beta"

async function checkForUpdates() {
    try {
        const response = await fetch(
            `https://apis.novasuite.one/api/patcher/check?app_id=${APP_ID}&channel=${CHANNEL}`
        );

        if (response.status === 404) {
            console.log("No updates available.");
            return null;
        }

        const manifest = await response.json();
        const latest = manifest.latest;

        // Compare versions (use a library like 'semver' for production)
        if (latest.version !== CURRENT_VERSION) {
            console.log(`Update available: ${latest.version}`);
            return latest;
        } else {
            console.log("App is up to date.");
            return null;
        }
    } catch (error) {
        console.error("Failed to check for updates:", error);
        return null;
    }
}

// Usage
checkForUpdates().then(update => {
    if (update) {
        showUpdateDialog(update);
    }
});

Python

import requests
from packaging import version

CURRENT_VERSION = "1.1.0"
APP_ID = "one.novasuite.myapp"
CHANNEL = "production"

def check_for_updates():
    try:
        response = requests.get(
            f"https://apis.novasuite.one/api/patcher/check",
            params={"app_id": APP_ID, "channel": CHANNEL}
        )

        if response.status_code == 404:
            print("No updates available.")
            return None

        response.raise_for_status()
        manifest = response.json()
        latest = manifest["latest"]

        # Compare versions
        if version.parse(latest["version"]) > version.parse(CURRENT_VERSION):
            print(f"Update available: {latest['version']}")
            return latest
        else:
            print("App is up to date.")
            return None

    except Exception as e:
        print(f"Failed to check for updates: {e}")
        return None

# Usage
update = check_for_updates()
if update:
    show_update_dialog(update)

C# (.NET)

using System;
using System.Net.Http;
using System.Text.Json;
using System.Threading.Tasks;

public class UpdateChecker
{
    private const string CURRENT_VERSION = "1.1.0";
    private const string APP_ID = "one.novasuite.myapp";
    private const string CHANNEL = "production";
    private static readonly HttpClient client = new HttpClient();

    public static async Task<Update?> CheckForUpdates()
    {
        try
        {
            var response = await client.GetAsync(
                $"https://apis.novasuite.one/api/patcher/check?app_id={APP_ID}&channel={CHANNEL}"
            );

            if (response.StatusCode == System.Net.HttpStatusCode.NotFound)
            {
                Console.WriteLine("No updates available.");
                return null;
            }

            response.EnsureSuccessStatusCode();
            var content = await response.Content.ReadAsStringAsync();
            var manifest = JsonSerializer.Deserialize<Manifest>(content);

            if (manifest?.Latest?.Version != CURRENT_VERSION)
            {
                Console.WriteLine($"Update available: {manifest.Latest.Version}");
                return manifest.Latest;
            }

            Console.WriteLine("App is up to date.");
            return null;
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Failed to check for updates: {ex.Message}");
            return null;
        }
    }
}

public class Manifest
{
    public string Id { get; set; }
    public string Channel { get; set; }
    public Update Latest { get; set; }
}

public class Update
{
    public string Version { get; set; }
    public string DownloadUrl { get; set; }
    public string Notes { get; set; }
    public string Hash { get; set; }
    public string InstallAction { get; set; }
    public string DisplayMode { get; set; }
    public string UpdateAction { get; set; }
}

Processing the Update

Once you've detected an update, you should:

  1. Verify the Hash: Download the file and verify its SHA-256 hash matches latest.hash
  2. Follow Install Instructions: Use latest.install_action to determine how to process the file:
  3. unzip: Extract contents to app directory
  4. execute: Run the downloaded file (installer)
  5. replace_file: Replace the app executable directly
  6. Apply Update Strategy: Use latest.update_action:
  7. replace: Overwrite existing files
  8. clean_install: Delete old files first
  9. delta: Apply only changed files
  10. Respect Display Mode: Use latest.display_mode:
  11. active: Show full UI with progress
  12. passive: Show minimal notification
  13. silent: Update in background

Best Practices

  1. Check on Startup: Check for updates when your app launches
  2. Don't Block: Run the check asynchronously
  3. Cache Results: Don't check more than once per session
  4. Respect User Preferences: Allow users to disable auto-updates
  5. Verify Integrity: Always check the SHA-256 hash before installing
  6. Handle Errors Gracefully: If the check fails, don't crash the app