Skip to content

🚀 Activation Flow

🌐 Online Activation

User Flow Diagram

┌─────────────────────────────────────────────────────────────┐
│                    ONLINE ACTIVATION                        │
└─────────────────────────────────────────────────────────────┘

    User launches plugin
    [No license found]
    ┌──────────────────────┐
    │ Enter License Key    │
    │ XXXX-XXXX-XXXX-XXXX │
    │                      │
    │ [Activate Online]    │
    └──────────────────────┘
    Generate machine fingerprint
    Send to license server:
      - License key
      - Machine ID
      - Product version
      - OS info
    ┌─────────────────────────────────┐
    │      SERVER VALIDATION          │
    ├─────────────────────────────────┤
    │ ✓ Key format correct?           │
    │ ✓ Key exists in database?       │
    │ ✓ Not expired?                  │
    │ ✓ Seat limit not exceeded?      │
    │ ✓ Not revoked/blacklisted?      │
    └─────────────────────────────────┘
    ┌─────────────────┐
    │ IF SUCCESS:     │
    │ - Generate      │
    │   license file  │
    │ - Return to     │
    │   client        │
    │ - Log activation│
    └─────────────────┘
    Plugin saves license.json locally
    ✅ ACTIVATION COMPLETE
    Plugin loads fully featured

API Endpoint

POST /api/v1/activate

// Request
{
  "license_key": "XXXX-XXXX-XXXX-XXXX",
  "machine_id": "a1b2c3d4e5f6",
  "product": "AudioLab Pro",
  "product_version": "1.0.1",
  "os": "Windows 10",
  "plugin_format": "VST3"
}
// Response (Success)
{
  "success": true,
  "license": {
    "version": 1,
    "license_key": "XXXX-XXXX-XXXX-XXXX",
    "email": "user@example.com",
    "name": "John Doe",
    "product": "AudioLab Pro",
    "license_type": "commercial",
    "issued_at": "2025-01-15T10:30:00Z",
    "expires_at": "2026-01-15T10:30:00Z",
    "seat_id": 1,
    "features": {
      "max_instances": 16,
      "oversampling": true
    },
    "signature": "BASE64_RSA_SIG..."
  }
}
// Response (Error)
{
  "success": false,
  "error_code": "SEAT_LIMIT_EXCEEDED",
  "message": "This license is already activated on 2 machines. Please deactivate one or contact support.",
  "support_url": "https://audiolab.com/support/license"
}

Error Codes

Code Message User Action
INVALID_KEY License key not found Check key, contact support
EXPIRED License has expired Renew subscription
SEAT_LIMIT_EXCEEDED Too many activations Deactivate old machine
REVOKED License revoked Contact support
VERSION_MISMATCH Product version not covered Upgrade license
NETWORK_ERROR Cannot reach server Try offline activation

Client Implementation

class OnlineActivation {
public:
    struct Result {
        bool success;
        std::string error_code;
        std::string message;
        nlohmann::json license_data;
    };

    Result activate(const std::string& license_key) {
        // Generate machine fingerprint
        std::string machine_id = MachineFingerprint::generate();

        // Prepare request
        nlohmann::json request = {
            {"license_key", license_key},
            {"machine_id", machine_id},
            {"product", "AudioLab Pro"},
            {"product_version", PRODUCT_VERSION},
            {"os", getOSName()},
            {"plugin_format", PLUGIN_FORMAT}
        };

        // Send HTTP POST request
        auto response = httpPost(
            "https://license.audiolab.com/api/v1/activate",
            request.dump(),
            {"Content-Type: application/json"}
        );

        if (response.status_code != 200) {
            return {false, "NETWORK_ERROR", "Cannot reach license server", {}};
        }

        auto response_json = nlohmann::json::parse(response.body);

        if (!response_json["success"].get<bool>()) {
            return {
                false,
                response_json["error_code"],
                response_json["message"],
                {}
            };
        }

        // Save license file
        auto license = response_json["license"];
        saveLicenseFile(license);

        return {true, "", "Activation successful", license};
    }

private:
    void saveLicenseFile(const nlohmann::json& license) {
        std::string license_path = getLicensePath();
        std::ofstream file(license_path);
        file << license.dump(2);
        file.close();

        // Set restrictive permissions (Windows)
        #ifdef _WIN32
        setFilePermissions(license_path, CURRENT_USER_ONLY);
        #endif
    }
};

💻 Offline Activation

When to Use Offline

  • Air-gapped studio (no internet)
  • Firewall blocks license server
  • Privacy-conscious users
  • Unreliable internet connection

User Flow Diagram

┌─────────────────────────────────────────────────────────────┐
│                   OFFLINE ACTIVATION                        │
└─────────────────────────────────────────────────────────────┘

    User launches plugin
    [No license found]
    ┌──────────────────────────────┐
    │ Enter License Key            │
    │ XXXX-XXXX-XXXX-XXXX         │
    │                              │
    │ [Activate Offline] <-- Click │
    └──────────────────────────────┘
    Plugin generates machine fingerprint
    ┌────────────────────────────────────┐
    │ Copy this code:                    │
    │                                    │
    │ XXXX-XXXX-XXXX-XXXX (license key)  │
    │ a1b2c3d4e5f6 (machine ID)          │
    │                                    │
    │ Or save to file: [Save .txt]       │
    └────────────────────────────────────┘
    User goes to activation website
    (on different device with internet)
    https://audiolab.com/activate-offline
    ┌──────────────────────────────┐
    │ Paste:                       │
    │ License Key: XXXX-XXXX...    │
    │ Machine ID:  a1b2c3d4e5f6    │
    │                              │
    │ [Generate License File]      │
    └──────────────────────────────┘
    Server validates & generates license.json
    User downloads license.json
    ┌──────────────────────────────┐
    │ In plugin:                   │
    │                              │
    │ [Import License File]        │
    │                              │
    │ Select: license.json         │
    └──────────────────────────────┘
    Plugin verifies signature
    ✅ ACTIVATION COMPLETE

Offline Activation Website

URL: https://audiolab.com/activate-offline

<!DOCTYPE html>
<html>
<head>
    <title>AudioLab Offline Activation</title>
</head>
<body>
    <h1>Offline License Activation</h1>

    <form id="activationForm">
        <label>License Key:</label>
        <input type="text" id="licenseKey" placeholder="XXXX-XXXX-XXXX-XXXX" required>

        <label>Machine ID:</label>
        <input type="text" id="machineId" placeholder="a1b2c3d4e5f6" required>

        <label>Product:</label>
        <select id="product">
            <option value="audiolab-pro">AudioLab Pro</option>
        </select>

        <button type="submit">Generate License File</button>
    </form>

    <div id="result"></div>

    <script>
        document.getElementById('activationForm').addEventListener('submit', async (e) => {
            e.preventDefault();

            const response = await fetch('/api/v1/activate-offline', {
                method: 'POST',
                headers: {'Content-Type': 'application/json'},
                body: JSON.stringify({
                    license_key: document.getElementById('licenseKey').value,
                    machine_id: document.getElementById('machineId').value,
                    product: document.getElementById('product').value
                })
            });

            const data = await response.json();

            if (data.success) {
                // Download license file
                const blob = new Blob([JSON.stringify(data.license, null, 2)],
                    {type: 'application/json'});
                const url = URL.createObjectURL(blob);
                const a = document.createElement('a');
                a.href = url;
                a.download = 'license.json';
                a.click();
            } else {
                alert('Error: ' + data.message);
            }
        });
    </script>
</body>
</html>

Plugin Offline Import

class OfflineActivation {
public:
    struct Result {
        bool success;
        std::string error_message;
    };

    Result importLicenseFile(const std::string& file_path) {
        // Read license file
        std::ifstream file(file_path);
        if (!file.is_open()) {
            return {false, "Cannot open license file"};
        }

        nlohmann::json license;
        try {
            file >> license;
        } catch (const std::exception& e) {
            return {false, "Invalid license file format"};
        }

        // Verify signature
        LicenseValidator validator;
        if (!validator.verifySignature(license)) {
            return {false, "Invalid license signature"};
        }

        // Check machine ID matches
        std::string current_machine_id = MachineFingerprint::generate();
        std::string license_machine_id = license["machine_id"];

        if (current_machine_id != license_machine_id) {
            return {false, "License not valid for this machine"};
        }

        // Check expiration
        if (isExpired(license)) {
            return {false, "License has expired"};
        }

        // Save to local storage
        saveLicenseFile(license);

        return {true, ""};
    }
};

🔄 Deactivation / Transfer

Why Allow Transfers?

  • User upgrades computer
  • User replaces motherboard (changes machine ID)
  • User sells old computer
  • User switches DAW on different machine

Without easy transfers → User feels locked in → Hostile experience

Self-Service Deactivation

From Plugin

┌─────────────────────────────────┐
│ License Status: ACTIVE          │
│                                 │
│ Machine: Desktop PC             │
│ Activated: 2025-01-15           │
│                                 │
│ [Deactivate This Machine]       │
└─────────────────────────────────┘
┌─────────────────────────────────┐
│ Are you sure?                   │
│                                 │
│ This will free up a seat for    │
│ activation on another machine.  │
│                                 │
│ [Yes, Deactivate]  [Cancel]     │
└─────────────────────────────────┘
   Send to server:
     - License key
     - Machine ID
     - Deactivate request
   Server removes seat
   Plugin deletes local license
   ✅ Deactivation complete

From Website

URL: https://audiolab.com/account/licenses

┌──────────────────────────────────────────────────┐
│ My Licenses                                      │
├──────────────────────────────────────────────────┤
│ AudioLab Pro - XXXX-XXXX-XXXX-XXXX              │
│                                                  │
│ Seats: 2 / 2 used                                │
│                                                  │
│ ┌────────────────────────────────────────────┐  │
│ │ Seat 1: Desktop PC (Windows)               │  │
│ │ Activated: 2025-01-15                      │  │
│ │ Last used: 2025-10-03                      │  │
│ │ [Deactivate]                               │  │
│ └────────────────────────────────────────────┘  │
│                                                  │
│ ┌────────────────────────────────────────────┐  │
│ │ Seat 2: Laptop (macOS)                     │  │
│ │ Activated: 2025-03-20                      │  │
│ │ Last used: 2025-09-28                      │  │
│ │ [Deactivate]                               │  │
│ └────────────────────────────────────────────┘  │
└──────────────────────────────────────────────────┘

Transfer Policy

Generous Limits

┌────────────────────────────────────────────┐
│ Transfer Allowance (Per Year)             │
├────────────────────────────────────────────┤
│ Self-service transfers:  3 free            │
│ Additional transfers:    Contact support   │
│                         (usually approved) │
│                                            │
│ Cooldown period:        24 hours          │
│ (prevents abuse)                           │
└────────────────────────────────────────────┘

API Implementation

POST /api/v1/deactivate

// Request
{
  "license_key": "XXXX-XXXX-XXXX-XXXX",
  "machine_id": "a1b2c3d4e5f6",
  "reason": "upgrading_computer" // Optional analytics
}
// Response (Success)
{
  "success": true,
  "message": "Seat deactivated successfully",
  "seats_remaining": 2,
  "seats_used": 1,
  "transfers_used_this_year": 1,
  "transfers_remaining": 2
}
// Response (Limit Exceeded)
{
  "success": false,
  "error_code": "TRANSFER_LIMIT_EXCEEDED",
  "message": "You have used all 3 free transfers this year. Please contact support for assistance.",
  "support_url": "https://audiolab.com/support",
  "transfers_used_this_year": 3
}

Server-Side Logic

from datetime import datetime, timedelta

def deactivate_seat(license_key: str, machine_id: str, user_id: str):
    # Find license
    license = db.licenses.find_one({"key": license_key})

    if not license:
        return {"success": False, "error": "LICENSE_NOT_FOUND"}

    # Find seat
    seat = next((s for s in license["seats"] if s["machine_id"] == machine_id), None)

    if not seat:
        return {"success": False, "error": "SEAT_NOT_FOUND"}

    # Check transfer limits
    this_year = datetime.now().year
    transfers = db.transfers.count({
        "license_key": license_key,
        "year": this_year
    })

    if transfers >= 3:
        return {
            "success": False,
            "error_code": "TRANSFER_LIMIT_EXCEEDED",
            "transfers_used": transfers
        }

    # Remove seat
    license["seats"].remove(seat)
    db.licenses.update_one({"key": license_key}, {"$set": {"seats": license["seats"]}})

    # Log transfer
    db.transfers.insert_one({
        "license_key": license_key,
        "user_id": user_id,
        "machine_id": machine_id,
        "year": this_year,
        "timestamp": datetime.now()
    })

    return {
        "success": True,
        "seats_remaining": license["max_seats"],
        "seats_used": len(license["seats"]),
        "transfers_used_this_year": transfers + 1,
        "transfers_remaining": 3 - (transfers + 1)
    }

📋 Activation UI/UX Best Practices

Clear Messaging

❌ Bad:

Error: 0x80041004
License validation failed.

✅ Good:

License Activation Failed

Your license key could not be validated.

Possible reasons:
• No internet connection (try offline activation)
• License key expired (renew at audiolab.com)
• Too many activations (deactivate old machine)

Need help? Visit audiolab.com/support

Progress Indication

void showActivationProgress() {
    showDialog({
        .title = "Activating License",
        .message = "Contacting license server...",
        .progress = 0.3,
        .cancelable = true
    });

    // After network request
    updateDialog({
        .message = "Validating license...",
        .progress = 0.6
    });

    // After validation
    updateDialog({
        .message = "Saving license...",
        .progress = 0.9
    });

    // Complete
    showDialog({
        .title = "Success!",
        .message = "AudioLab Pro is now activated.",
        .icon = "✅",
        .autoClose = 3000
    });
}