Licencje
Zarządzaj weryfikacją i aktywacją licencji oraz śledzeniem urządzeń.
429 Too Many Requests z nagłówkiem Retry-After: 60 aż do zresetowania okna.Weryfikacja licencji
Zweryfikuj i aktywuj klucz licencyjny. Ten endpoint ma limit 5 żądań na minutę na adres IP.
Endpoint: POST /api/licenses/validate
| Parametr | Typ | Wymagany | Opis |
|---|---|---|---|
license_key | string | Tak | Klucz licencyjny do zweryfikowania |
device_id | string | Tak | Stabilny, unikalny identyfikator aktywowanego urządzenia. Wysyłaj za każdym razem tę samą wartość dla danego urządzenia: to dzięki niej urządzenie zajmuje i ponownie odzyskuje swoje miejsce w licencji |
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?;
Odpowiedź (sukces):
{
"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
}
}
Odpowiedź (błąd):
{
"statusCode": 400,
"statusMessage": "Invalid licence key or validation failed"
}
| Status | Kiedy |
|---|---|
400 | Brakuje license_key lub device_id, wartość jest pusta lub za długa albo klucz jest nieznany, nieaktywny lub wygasły |
409 | Wszystkie miejsca w licencji są już zajęte przez inne urządzenia i żadne nie było nieaktywne wystarczająco długo, by można je było odzyskać |
429 | Przekroczono limit żądań, zobacz Limity żądań |
400 nigdy nie wskazuje, które pole było błędne: przed ponowną próbą upewnij się, że license_key i device_id są obecne i niepuste.Dezaktywacja licencji
Wymagane uwierzytelnienieWymaga ciasteczka sesji session_token właściciela licencji (zobacz Uwierzytelnianie): możesz dezaktywować tylko licencję, której jesteś właścicielem.
Dezaktywuj licencję na konkretnym urządzeniu lub na wszystkich urządzeniach.
Endpoint: POST /api/licenses/deactivate
| Parametr | Typ | Wymagany | Opis |
|---|---|---|---|
license_key | string | Tak | Klucz licencyjny do dezaktywacji |
device_id | string | Nie | Konkretne urządzenie do dezaktywacji (pomiń, aby objąć wszystkie urządzenia) |
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?;
Odpowiedź:
{
"success": true,
"message": "Device deactivated successfully",
"deactivated_count": 1,
"remaining_activations": 4
}
remaining_activations to liczba miejsc nadal używanych po dezaktywacji, czyli liczba różnych urządzeń, które pozostają aktywne w licencji. Nie jest to liczba wolnych miejsc. Dezaktywacja wszystkich urządzeń zwraca więc 0. Liczbę wolnych miejsc oblicz jako activation_limit - remaining_activations, używając activation_limit z GET /api/licenses/status. Bez device_id komunikat brzmi „All devices deactivated successfully”; deactivated_count to liczba miejsc zwolnionych przez to wywołanie.Status licencji
Wymagane uwierzytelnienieWymaga ciasteczka sesji session_token właściciela licencji (zobacz Uwierzytelnianie): możesz sprawdzać tylko licencję, której jesteś właścicielem.
Sprawdź bieżący status licencji. Limit wynosi 30 żądań na minutę na adres IP.
Endpoint: GET /api/licenses/status
| Parametr | Typ | Wymagany | Opis |
|---|---|---|---|
license_key | query | Tak | Klucz licencyjny do sprawdzenia |
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?;
Odpowiedź:
{
"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"
}
]
}
Cykl życia licencji
Limity żądań
Endpointy licencji mają limity żądań na adres IP w stałym, 60-sekundowym oknie. Przy odpowiedzi 429 zwracany jest jeden nagłówek:
| Nagłówek | Opis |
|---|---|
Retry-After | Liczba sekund do zresetowania okna (zawsze 60) |
Limity żądań według endpointu
| Endpoint | Żądania / 60 s | Poziom |
|---|---|---|
/api/licenses/validate | 5 | Ścisły |
/api/licenses/status | 30 | Standardowy |
/api/licenses/deactivate | 30 | Standardowy |
POST /api/licenses/validate stosuje limit Ścisły dwukrotnie: raz na adres IP i raz według przesłanego license_key, dzięki czemu pojedynczego klucza nie da się zasypywać żądaniami z wielu adresów IP.
429 Too Many Requests przez pozostałą część 60-sekundowego okna. Czas blokady nie jest stopniowo wydłużany ani zwiększany.Typy licencji
Licencja odpowiada jednemu z bieżących poziomów planów. Wiążący zestaw funkcji i limitów dla każdego poziomu to ten, który pokazuje strona z cennikiem, zobacz Porównaj plany.
| Poziom | Dla kogo | Najważniejsze dodatki względem niższego poziomu |
|---|---|---|
free | Stały darmowy plan, bez karty, bez daty wygaśnięcia | Prosty pilot do prezentacji: jeden pokój, jeden prezenter, udostępnianie ekranu ze znakiem wodnym i Stream Deck; wszystkie pozostałe funkcje są zablokowane |
presenter | Prezenterzy | Timer Pro, czat, rysowanie, wielu hostów i NDI |
pro (Studio HD) | Samodzielni producenci | Rozmówcy, własne pokoje, udostępnianie wideo i podstawowe funkcje Studio |
ultra (Studio 4K) | Zaawansowani użytkownicy i streamerzy | Nieograniczona liczba pokoi, zapisane motywy kolorystyczne marki, warstwy, nagrywanie ISO, powtórki i szerszy zestaw narzędzi Studio |
studio (Studio 8K) | Zespoły produkcyjne | Projektant układu pokoju, branding whitelabel, Client API, klucze API, własne domeny, zespołowe licencje na miejsca ze wspólnej puli |
enterprise | Duże organizacje i działy zakupów | SSO, SCIM i niestandardowe role zespołowe, roczne umowy rozliczane za miejsce |