Skip to main content

Endpoint

POST /api/websocket-voice/token

Request a JWT token for WebSocket authentication

Request

Headers

Content-Type: application/json
Accept: application/json

Body Parameters

ParameterTypeRequiredDescription
apiKeystringYour device API key
deviceIdstringUnique identifier for your device

Request Example

{
  "apiKey": "sk_live_1234567890abcdef",
  "deviceId": "device_uuid_4567890abcdef123"
}
cURL Example
curl -X POST https://api.thesavants.ai/api/websocket-voice/token \
  -H "Content-Type: application/json" \
  -d '{
    "apiKey": "sk_live_1234567890abcdef",
    "deviceId": "device_uuid_4567890abcdef123"
  }'

Response

Success Response

Status Code: 200 OK Headers:
Content-Type: application/json
Cache-Control: no-cache, no-store, must-revalidate
Body:
{
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJkZXZpY2VfNDU2Nzg5MGFiY2RlZjEyMyIsImV4cCI6MTYzOTk4NzY1NCwiaWF0IjoxNjM5OTg3NTk0fQ.signature"
}
Response Schema:
FieldTypeDescription
tokenstringJWT token valid for 1 minute

Error Responses

  • 400 Bad Request
  • 401 Unauthorized
  • 429 Too Many Requests
  • 500 Server Error
Cause: Missing or invalid request parameters
{
  "error": {
    "code": "INVALID_REQUEST",
    "message": "Missing required field: apiKey",
    "details": {
      "field": "apiKey",
      "expected": "string"
    }
  }
}
Common Issues:
  • Missing apiKey or deviceId in request body
  • Invalid JSON format
  • Empty string values

JWT Token Details

Token Structure

The returned JWT contains the following claims:
ClaimDescription
subSubject - Your device ID
iatIssued at timestamp
expExpiration timestamp (iat + 60 seconds)
audAudience - “voice-api”
issIssuer - “thesavants.ai”

Token Validation

Example JWT Payload:
{
  "sub": "device_uuid_4567890abcdef123",
  "iat": 1639987594,
  "exp": 1639987654,
  "aud": "voice-api",
  "iss": "thesavants.ai"
}

Security Notes

Token Lifespan: Tokens expire after exactly 60 seconds and cannot be renewed. Request a new token for each WebSocket connection.

Single Use

Each token should only be used once for one WebSocket connection

No Caching

Never cache or store tokens beyond their intended use

Secure Transport

Always use HTTPS for token requests

Error Handling

Implement exponential backoff for rate limit errors

Rate Limiting

  • Limit: 60 requests per minute per device
  • Window: Rolling 60-second window
  • Reset: Rate limit resets after 60 seconds from first request
Rate Limit Headers:
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 45
X-RateLimit-Reset: 1639987654

Implementation Examples

  • Flutter/Dart
  • JavaScript
  • Python
Future<String> fetchAuthToken() async {
  final response = await http.post(
    Uri.parse('${apiBaseUrl}/api/websocket-voice/token'),
    headers: {
      'Content-Type': 'application/json',
      'Accept': 'application/json',
    },
    body: jsonEncode({
      'apiKey': apiKey,
      'deviceId': deviceId,
    }),
  );

  if (response.statusCode == 200) {
    final data = jsonDecode(response.body);
    return data['token'];
  } else {
    final error = jsonDecode(response.body);
    throw AuthenticationException(
      error['error']['code'],
      error['error']['message'],
    );
  }
}