Licences
Gérez la validation et l'activation des licences ainsi que le suivi des appareils.
429 Too Many Requests avec un en-tête Retry-After: 60 jusqu'à la réinitialisation de la fenêtre.Valider une licence
Validez et activez une clé de licence. Ce point de terminaison est limité à 5 requêtes par minute par adresse IP.
Point de terminaison : POST /api/licenses/validate
| Paramètre | Type | Obligatoire | Description |
|---|---|---|---|
license_key | string | Oui | Clé de licence à valider |
device_id | string | Oui | Identifiant stable et unique de l'appareil à activer. Envoyez toujours la même valeur pour un appareil donné : c'est elle qui attribue et réattribue le poste de cet appareil |
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?;
Réponse (succès) :
{
"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
}
}
Réponse (erreur) :
{
"statusCode": 400,
"statusMessage": "Invalid licence key or validation failed"
}
| Statut | Cas |
|---|---|
400 | license_key ou device_id est absent, vide ou trop long, ou la clé est inconnue, inactive ou expirée |
409 | Tous les postes de la licence sont déjà occupés par d'autres appareils, et aucun n'est resté inactif assez longtemps pour être récupéré |
429 | Limite de débit dépassée, voir Limitation de débit |
400 n'indique donc jamais quel champ est en cause : vérifiez que license_key et device_id sont tous deux présents et non vides avant de réessayer.Désactiver une licence
Authentification requiseNécessite le cookie de session session_token du propriétaire de la licence (voir Authentification) : vous ne pouvez désactiver qu'une licence qui vous appartient.
Désactivez une licence sur un appareil précis ou sur tous les appareils.
Point de terminaison : POST /api/licenses/deactivate
| Paramètre | Type | Obligatoire | Description |
|---|---|---|---|
license_key | string | Oui | Clé de licence à désactiver |
device_id | string | Non | Appareil précis à désactiver (à omettre pour tous les appareils) |
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?;
Réponse :
{
"success": true,
"message": "Device deactivated successfully",
"deactivated_count": 1,
"remaining_activations": 4
}
remaining_activations correspond au nombre de postes encore utilisés après la désactivation, c'est-à-dire au nombre d'appareils distincts toujours actifs sur la licence. Il ne s'agit pas du nombre de postes libres. La désactivation de tous les appareils renvoie donc 0. Calculez les postes libres avec activation_limit - remaining_activations, en utilisant la valeur activation_limit renvoyée par GET /api/licenses/status. Sans device_id, le message est « All devices deactivated successfully » ; deactivated_count correspond au nombre de postes libérés par cet appel.Statut de la licence
Authentification requiseNécessite le cookie de session session_token du propriétaire de la licence (voir Authentification) : vous ne pouvez consulter qu'une licence qui vous appartient.
Vérifiez le statut actuel d'une licence. Limité à 30 requêtes par minute par IP.
Point de terminaison : GET /api/licenses/status
| Paramètre | Type | Obligatoire | Description |
|---|---|---|---|
license_key | query | Oui | Clé de licence à vérifier |
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?;
Réponse :
{
"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"
}
]
}
Cycle de vie d'une licence
Limitation de débit
Les points de terminaison de licence sont soumis à une limitation de débit par IP sur une fenêtre fixe de 60 secondes. En cas de 429, un en-tête est renvoyé :
| En-tête | Description |
|---|---|
Retry-After | Nombre de secondes avant la réinitialisation de la fenêtre (toujours 60) |
Limites de débit par point de terminaison
| Point de terminaison | Requêtes / 60 s | Niveau |
|---|---|---|
/api/licenses/validate | 5 | Strict |
/api/licenses/status | 30 | Standard |
/api/licenses/deactivate | 30 | Standard |
POST /api/licenses/validate applique deux fois la limite Strict : une fois par IP, et une fois par license_key soumise, de sorte qu'une même clé ne puisse pas être bombardée de requêtes depuis de nombreuses IP.
429 Too Many Requests pendant le reste de la fenêtre de 60 secondes. Il n'existe aucune durée de blocage progressive ou croissante.Types de licences
Chaque licence correspond à l'un des niveaux d'offre actuels. L'ensemble de référence des fonctionnalités et des limites de chaque niveau est celui qu'affiche la page des tarifs, voir Comparer les offres.
| Niveau | Public visé | Principaux ajouts par rapport au niveau inférieur |
|---|---|---|
free | Offre gratuite permanente, sans carte bancaire, sans expiration | Une simple télécommande de présentation : une salle, un présentateur, le partage d'écran avec filigrane et Stream Deck ; toutes les autres fonctionnalités sont verrouillées |
presenter | Présentateurs | Timer Pro, chat, dessin, multi-hôte et NDI |
pro (Studio HD) | Producteurs indépendants | Appelants, salles personnalisées, partage vidéo et les essentiels de Studio |
ultra (Studio 4K) | Utilisateurs avancés et streamers | Salles illimitées, thèmes de couleurs de marque enregistrés, calques, enregistrement ISO, replay et la panoplie élargie d'outils Studio |
studio (Studio 8K) | Équipes de production | Concepteur de disposition des salles, marque blanche, la Client API, les clés API, les domaines personnalisés, les licences d'équipe mutualisées par poste |
enterprise | Grandes organisations et services achats | SSO, SCIM et rôles d'équipe personnalisés, contrats annuels par poste |
WebSocket en temps réel
Pilotez une salle Cliqer depuis votre propre logiciel comme avec une télécommande de présentation : diapositives, minuteur, pointeur laser et messages à l'hôte
Sujets avancés
Fonctionnalités et configurations professionnelles pour les déploiements en entreprise et les configurations d'événements complexes.