Skip to content

Quickstart

Ten minutes, curl, and (for the offline half) Python. Nothing to install.

Value Where to get it
API base URL https://api.waveformanager.com for every merchant.
A license key Place a test order, or have the merchant issue a not-for-resale (NFR) key from the Waveform admin. Keys look like ACME-7F3K-9QPD-2MXR.
Product ID (offline products) The product’s internal ID, shown on the Integration page of the Waveform admin. It is a short opaque string, never a store SKU or a Shopify GID.
Public key (offline products) Also on the Integration page. It is public and safe to ship inside your app.

An online product asks the API on each use. One request:

Terminal window
curl -sX POST https://api.waveformanager.com/v1/validate \
-H 'content-type: application/json' \
-d '{"key":"ACME-7F3K-9QPD-2MXR","instanceId":"sess_123"}'

A valid, active license answers 200:

{
"ok": true, "status": "active", "mode": "online",
"features": ["pro"], "expiresAt": 1824014964,
"sessions": { "used": 1, "max": 2 },
"usage": { "used": 0, "limit": 3, "period": "2026-10" }
}

Send the same instanceId again and the session is refreshed rather than counted twice. A different instanceId beyond the product’s session cap gets 409 with {"error":"session-limit"}. An unknown key is 404 invalid-key; a revoked or expired one is 403. Full detail in the Online integration guide.

An offline product activates once, receives a signed token, and from then on verifies it without the network.

  1. Compute this machine’s fingerprint. Any stable machine ID works for a test; a real app uses the OS machine ID (see Core concepts).

    Terminal window
    RAW_ID="my-test-machine-1" # a real app: MachineGuid / IOPlatformUUID / machine-id
    APP_SALT="my-app-fp-salt-v1" # a constant unique to your product, never changed after release
    FP=$(printf %s "$RAW_ID" | tr 'A-Z' 'a-z' \
    | openssl dgst -sha256 -hmac "$APP_SALT" -binary \
    | openssl base64 -A | tr '+/' '-_' | tr -d '=')
    echo "$FP"
  2. Activate the key on this device.

    Terminal window
    curl -sX POST https://api.waveformanager.com/v1/activate \
    -H 'content-type: application/json' \
    -d "{\"key\":\"ACME-7F3K-9QPD-2MXR\",\"fingerprint\":\"$FP\",\"deviceName\":\"Studio Mac\",\"productId\":\"<product-id>\"}" \
    > activation.json

    The response carries the signed token, the server’s publicKey, and the device record:

    {
    "token": "<payload>.<signature>",
    "publicKey": "VXdxEEnp3JGgxVOXgDlo1BwIEu_UuluzUK5e-sIG9IQ",
    "device": { "id": "id_2", "name": "Studio Mac", "createdAt": 1792478978, "lastSeenAt": 1792478978 },
    "reactivated": false,
    "rebound": false
    }
  3. Verify the token locally. This is what your app does on every launch, with no network. In production you embed the public key from the Integration page rather than trusting the one in the response; the response copy is for this walkthrough.

    import json, base64, hmac, time
    from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey
    def b64d(s): return base64.urlsafe_b64decode(s + "=" * (-len(s) % 4))
    act = json.load(open("activation.json"))
    token, public_key = act["token"], act["publicKey"]
    fingerprint = "<the value of $FP>"
    payload_b64, sig_b64 = token.split(".")
    # 1. signature over the exact payload bytes (raises InvalidSignature if forged)
    Ed25519PublicKey.from_public_bytes(b64d(public_key)).verify(b64d(sig_b64), b64d(payload_b64))
    # 2. only now trust the claims
    claims = json.loads(b64d(payload_b64))
    assert claims["alg"] == "ed25519" and claims["v"] == 1
    assert hmac.compare_digest(claims["fp"], fingerprint) # bound to this machine
    assert time.time() <= claims["exp"] + claims["grace"] * 86400 # inside lease + grace
    print("licensed, features:", claims["feat"])