Licenties
Beheer licentievalidatie, activering en het bijhouden van apparaten.
429 Too Many Requests met een Retry-After: 60-header terug totdat het venster opnieuw begint.Licentie valideren
Valideer en activeer een licentiesleutel. Voor dit endpoint geldt een limiet van 5 verzoeken per minuut per IP-adres.
Endpoint: POST /api/licenses/validate
| Parameter | Type | Verplicht | Beschrijving |
|---|---|---|---|
license_key | string | Ja | Te valideren licentiesleutel |
device_id | string | Ja | Stabiele, unieke identificatie van het apparaat dat wordt geactiveerd. Stuur voor een bepaald apparaat altijd dezelfde waarde mee: daarmee wordt de licentieplek van dat apparaat geclaimd en opnieuw geclaimd |
curl -X POST "$BASE_URL/api/licenses/validate" \
-H "Content-Type: application/json" \
-d '{"license_key":"XXXX-XXXX-XXXX-XXXX","device_id":"device_abc123"}'
interface LicenseValidation {
valid: boolean
license: {
id: string
status: string
product: object
activation_date: string
expiration_date: string
current_activations: number
}
}
const result: LicenseValidation = await $fetch('/api/licenses/validate', {
method: 'POST',
body: {
license_key: 'XXXX-XXXX-XXXX-XXXX',
device_id: 'device_abc123'
}
})
import requests
response = requests.post(
"$BASE_URL/api/licenses/validate",
json={
"license_key": "XXXX-XXXX-XXXX-XXXX",
"device_id": "device_abc123"
}
)
result = response.json()
package main
import (
"bytes"
"encoding/json"
"net/http"
)
func validateLicense() {
payload := map[string]string{
"license_key": "XXXX-XXXX-XXXX-XXXX",
"device_id": "device_abc123",
}
body, _ := json.Marshal(payload)
resp, _ := http.Post(
"$BASE_URL/api/licenses/validate",
"application/json",
bytes.NewBuffer(body),
)
defer resp.Body.Close()
}
<?php
$response = file_get_contents(
'$BASE_URL/api/licenses/validate',
false,
stream_context_create([
'http' => [
'method' => 'POST',
'header' => 'Content-Type: application/json',
'content' => json_encode([
'license_key' => 'XXXX-XXXX-XXXX-XXXX',
'device_id' => 'device_abc123'
])
]
])
);
$result = json_decode($response, true);
use reqwest::Client;
use serde_json::json;
let client = Client::new();
let response = client
.post("$BASE_URL/api/licenses/validate")
.json(&json!({
"license_key": "XXXX-XXXX-XXXX-XXXX",
"device_id": "device_abc123"
}))
.send()
.await?;
Antwoord (succes):
{
"valid": true,
"license": {
"id": "uuid",
"status": "active",
"product": { "id": "uuid", "name": "studio", "features": ["client_api", "api_keys"] },
"activation_date": "2024-01-01T00:00:00Z",
"expiration_date": "2025-12-31T23:59:59Z",
"current_activations": 1
}
}
Antwoord (fout):
{
"statusCode": 400,
"statusMessage": "Invalid licence key or validation failed"
}
| Status | Wanneer |
|---|---|
400 | license_key of device_id ontbreekt, is leeg of te lang, of de sleutel is onbekend, inactief of verlopen |
409 | Alle licentieplekken zijn al bezet door een ander apparaat en geen daarvan was lang genoeg inactief om terug te nemen |
429 | Rate limit overschreden, zie Rate limiting |
400 vertelt dus nooit welk veld fout was: controleer of license_key en device_id allebei aanwezig en niet leeg zijn voordat je het opnieuw probeert.Licentie deactiveren
Authenticatie vereistVereist de sessiecookie session_token van de licentie-eigenaar (zie Authenticatie): je kunt alleen een licentie deactiveren die van jou is.
Deactiveer een licentie op een specifiek apparaat of op alle apparaten.
Endpoint: POST /api/licenses/deactivate
| Parameter | Type | Verplicht | Beschrijving |
|---|---|---|---|
license_key | string | Ja | Te deactiveren licentiesleutel |
device_id | string | Nee | Specifiek apparaat om te deactiveren (weglaten voor alle apparaten) |
curl -X POST "$BASE_URL/api/licenses/deactivate" \
-b cookies.txt \
-H "Content-Type: application/json" \
-d '{"license_key":"XXXX-XXXX-XXXX-XXXX","device_id":"device_abc123"}'
const result = await $fetch('/api/licenses/deactivate', {
method: 'POST',
// session cookie (session_token) is sent automatically same-origin
body: {
license_key: 'XXXX-XXXX-XXXX-XXXX',
device_id: 'device_abc123'
}
})
import requests
response = requests.post(
"$BASE_URL/api/licenses/deactivate",
headers={"Cookie": f"session_token={token}"},
json={
"license_key": "XXXX-XXXX-XXXX-XXXX",
"device_id": "device_abc123"
}
)
req, _ := http.NewRequest("POST",
"$BASE_URL/api/licenses/deactivate",
bytes.NewBuffer(body))
req.Header.Set("Cookie", "session_token="+token)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
<?php
$response = file_get_contents(
'$BASE_URL/api/licenses/deactivate',
false,
stream_context_create([
'http' => [
'method' => 'POST',
'header' => "Content-Type: application/json\r\n" .
"Cookie: session_token=$token",
'content' => json_encode([
'license_key' => 'XXXX-XXXX-XXXX-XXXX',
'device_id' => 'device_abc123'
])
]
])
);
let response = client
.post("$BASE_URL/api/licenses/deactivate")
.header("Cookie", format!("session_token={}", token))
.json(&json!({
"license_key": "XXXX-XXXX-XXXX-XXXX",
"device_id": "device_abc123"
}))
.send()
.await?;
Antwoord:
{
"success": true,
"message": "Device deactivated successfully",
"deactivated_count": 1,
"remaining_activations": 4
}
remaining_activations het aantal licentieplekken dat na de deactivering nog in gebruik is, oftewel het aantal unieke apparaten dat nog actief is op de licentie. Het is niet het aantal vrije plekken. Als je alle apparaten deactiveert, krijg je dus 0 terug. Bereken het aantal vrije plekken als activation_limit - remaining_activations, met activation_limit uit GET /api/licenses/status. Zonder device_id luidt de melding "All devices deactivated successfully"; deactivated_count is het aantal plekken dat deze aanroep heeft vrijgegeven.Licentiestatus
Authenticatie vereistVereist de sessiecookie session_token van de licentie-eigenaar (zie Authenticatie): je kunt alleen een licentie inzien die van jou is.
Controleer de huidige status van een licentie. Hiervoor geldt een limiet van 30 verzoeken per minuut per IP-adres.
Endpoint: GET /api/licenses/status
| Parameter | Type | Verplicht | Beschrijving |
|---|---|---|---|
license_key | query | Ja | Te controleren licentiesleutel |
curl -X GET "$BASE_URL/api/licenses/status?license_key=XXXX-XXXX-XXXX-XXXX" \
-b cookies.txt
const status = await $fetch('/api/licenses/status', {
// session cookie (session_token) is sent automatically same-origin
query: { license_key: 'XXXX-XXXX-XXXX-XXXX' }
})
import requests
response = requests.get(
"$BASE_URL/api/licenses/status",
headers={"Cookie": f"session_token={token}"},
params={"license_key": "XXXX-XXXX-XXXX-XXXX"}
)
req, _ := http.NewRequest("GET",
"$BASE_URL/api/licenses/status?license_key=XXXX-XXXX-XXXX-XXXX",
nil)
req.Header.Set("Cookie", "session_token="+token)
resp, _ := http.DefaultClient.Do(req)
<?php
$response = file_get_contents(
'$BASE_URL/api/licenses/status?license_key=XXXX-XXXX-XXXX-XXXX',
false,
stream_context_create([
'http' => [
'header' => "Cookie: session_token=$token"
]
])
);
let response = client
.get("$BASE_URL/api/licenses/status")
.header("Cookie", format!("session_token={}", token))
.query(&[("license_key", "XXXX-XXXX-XXXX-XXXX")])
.send()
.await?;
Antwoord:
{
"license": {
"id": "uuid",
"license_key": "XXXX-XXXX-XXXX-XXXX",
"status": "active",
"purchase_date": "2024-01-01T00:00:00Z",
"activation_date": "2024-01-01T00:00:00Z",
"expiration_date": "2025-12-31T23:59:59Z",
"days_until_expiration": 365,
"activation_limit": 5,
"current_activations": 2,
"available_activations": 3,
"is_expired": false,
"is_active": true,
"product": { "id": "uuid", "name": "Studio 8K", "description": "...", "features": [] },
"user": { "id": "uuid", "first_name": "Jane", "last_name": "Doe", "email": "user@example.com" }
},
"active_devices": [
{
"id": "uuid",
"device_id": "device_abc123",
"device_name": "Studio Mac",
"platform": "macos",
"app_version": "3.1.2",
"activated_at": "2024-01-01T00:00:00Z",
"last_seen_at": "2024-01-02T09:00:00Z",
"ip_address": "192.168.1.1"
}
]
}
Levenscyclus van een licentie
Rate limiting
Voor licentie-endpoints geldt een rate limit per IP-adres binnen een vast venster van 60 seconden. Bij een 429 wordt één header meegestuurd:
| Header | Beschrijving |
|---|---|
Retry-After | Aantal seconden totdat het venster opnieuw begint (altijd 60) |
Rate limits per endpoint
| Endpoint | Verzoeken / 60s | Niveau |
|---|---|---|
/api/licenses/validate | 5 | Streng |
/api/licenses/status | 30 | Standaard |
/api/licenses/deactivate | 30 | Standaard |
POST /api/licenses/validate past de strenge limiet twee keer toe: één keer per IP-adres en één keer op basis van de ingediende license_key, zodat één sleutel niet vanaf veel IP-adressen kan worden bestookt.
429 Too Many Requests terug voor de rest van het venster van 60 seconden. Er is geen oplopende of escalerende blokkeerduur.Licentietypen
Een licentie valt onder een van de huidige abonnementsniveaus. De doorslaggevende set functies en limieten per niveau is wat de prijspagina toont, zie Abonnementen vergelijken.
| Niveau | Voor wie | Belangrijkste toevoegingen ten opzichte van het niveau eronder |
|---|---|---|
free | Permanent gratis abonnement, geen creditcard, geen vervaldatum | Een eenvoudige presentatieclicker: één ruimte, één presentator, schermdeling met watermerk en Stream Deck; alle andere functies zijn vergrendeld |
presenter | Presentatoren | Timer Pro, chat, tekenen, multi-host en NDI |
pro (Studio HD) | Soloproducers | Bellers, aangepaste ruimtes, video delen en de essentiële Studio-functies |
ultra (Studio 4K) | Power users en streamers | Onbeperkt aantal ruimtes, opgeslagen kleurthema's voor je merk, lagen, ISO-opname, replay en de uitgebreidere Studio-toolset |
studio (Studio 8K) | Productieteams | Ontwerper voor ruimte-indelingen, whitelabelbranding, de Client API, API-sleutels, eigen domeinen, gedeelde teamlicenties per plek |
enterprise | Grote organisaties en inkoopafdelingen | SSO, SCIM en aangepaste teamrollen, jaarcontracten per plek |
Realtime via WebSocket
Bedien een Cliqer-ruimte vanuit je eigen software als een presentatieclicker op afstand, met dia's, de timer, een laserpointer en berichten aan de host
Geavanceerde onderwerpen
Professionele functies en configuraties voor enterprise-implementaties en complexe evenementopstellingen.