Website Identity

Persistent installation UUID and normalized domain requirements for license clients

Overview

WooNooW identifies each licensed website using two required values together:

text
persistent installation UUID + normalized domain

This combined identity is used for activation, validation, deactivation by identity, OAuth activation, and software update checks. Neither value is accepted as a fallback for the other.

Installation UUID

installation_id must be a canonical UUID using the 8-4-4-4-12 hexadecimal format:

text
550e8400-e29b-41d4-a716-446655440000

A client must:

  1. generate it once using a cryptographically secure random UUID generator;
  2. store it persistently for the installation;
  3. reuse the same value for every license and update request within the same client integration scope;
  4. keep that scope stable for the lifetime of the installation—the WooNooW reference updater scopes storage by store API URL + product slug;
  5. avoid deriving it from the domain, license key, hardware, or personal data.

WordPress example:

php
$option_name    = 'my_product_installation_id';
$installation_id = strtolower(trim((string) get_option($option_name, '')));

if (!preg_match('/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/', $installation_id)) {
    $installation_id = wp_generate_uuid4();
    update_option($option_name, $installation_id, false);
}

Do not generate a new UUID on every request or routine plugin update. Losing the stored UUID causes the same domain to be treated as a different installation.

Domain normalization

Clients send the current site URL as domain for license operations and as site_url for update checks. WooNooW normalizes it by:

  • removing the scheme, path, query, and fragment;
  • lowercasing the hostname;
  • removing a trailing dot;
  • removing HTTP port 80 and HTTPS port 443;
  • preserving non-default ports;
  • treating www.example.com and example.com as different domains.

Send a canonical URL such as home_url() from WordPress. Authorization decisions use the server-normalized value.

Identity semantics

Installation UUIDNormalized domainResult
SameSameSame identity; activation retries are idempotent
SameDifferentDifferent identity
DifferentSameDifferent identity

machine_id may be sent as optional metadata, but it does not form the canonical identity and cannot replace either required value.

Activation snapshots and limits

When a license is activated with a valid UUID + domain pair, WooNooW records an authoritative activation row in woonoow_license_activations:

  • Identity binding: identity_key (SHA-256 hash of installation_id and normalized domain), domain, domain_normalized, and installation_id.
  • Telemetry snapshot: Client IP address (ip_address), client user agent (user_agent), and optional machine identifier (machine_id).
  • Lifecycle state: status (active or deactivated), UTC activation time (activated_at), UTC deactivation time (deactivated_at), and an incrementing activation_revision.

Unlimited activations (0)

An activation_limit of 0 designates an explicitly unlimited license. When activation_limit === 0:

  • The license has no ceiling on concurrent active website identities.
  • API responses report activations_remaining: -1.
  • The WooNooW administration interface displays seat usage as activation_count / ∞ with remaining seats labeled as "Unlimited".

Positive values enforce an explicit maximum count of concurrent active identities.

Stateless validation (no last validation tracking)

Periodic client validation (POST /licenses/validate) verifies that the license remains valid and that the requesting UUID + domain pair has an active activation row.

In the merchant administration interface (Products → Licenses → License Details), operators can review:

  • Customer details: Customer ID (user_id), name, and email.
  • Seat allocation: Current active seats versus limit (count / limit or count / ∞).
  • Activation history: Domain or machine ID, client IP address, initial activation time (activated_at), and current status (active or deactivated).

Domain changes and migrations

A domain change creates a new identity even when the installation UUID remains unchanged. To release the old activation slot:

  1. deactivate the old identity using its activation_id, or its old UUID + domain pair;
  2. activate the same persistent UUID with the new domain;
  3. continue using the new domain for validation and update checks.

If the old site is no longer accessible, the customer can deactivate it from My Account → Licenses when merchant settings allow deactivation.

Requests that require identity

The pair is mandatory on:

  • POST /wp-json/woonoow/v1/licenses/activate;
  • POST /wp-json/woonoow/v1/licenses/validate;
  • POST /wp-json/woonoow/v1/licenses/deactivate when not using activation_id;
  • OAuth activation requests and token exchange;
  • GET|POST /wp-json/woonoow/v1/software/check for protected products;
  • POST /wp-json/woonoow/v1/software/package for protected products; and
  • the protected external-release link route.

See Licensing API, OAuth Activation Flow, Software Updates Integration, and Software Distribution API for complete request examples.

Last updated Sep 8, 2026