SDKs
Glytos is a plain REST API described by OpenAPI, so every language works. Three have hand-written SDKs because they are the most common places to start; everything else is either a generated client or a plain HTTP call, and both are first-class.
Web
Voice calls from a browser, over WebRTC.
Node
Server-side TypeScript: agents, calls, sessions, webhooks.
Python
The same surface, server-side, in Python.
Which one
The web SDK is for one job: talking to an agent from a browser. It never sees your API key.
The Node and Python SDKs are for your backend. They cover the same surface, so pick the one your stack already speaks.
Only the web SDK belongs in a browser. The server SDKs take an API key, and an API key in front-end code is a key anyone can read.
Any other language
Two ways, both supported.
Generate a client
Point any OpenAPI generator at the spec:
openapi-generator-cli generate \
-i https://api.glytos.com/api/v1/openapi.json \
-g php \
-o ./glytos-phpopenapi-generator-cli generate \
-i https://api.glytos.com/api/v1/openapi.json \
-g go \
-o ./glytos-goopenapi-generator-cli generate \
-i https://api.glytos.com/api/v1/openapi.json \
-g java \
-o ./glytos-javaopenapi-generator-cli generate \
-i https://api.glytos.com/api/v1/openapi.json \
-g csharp \
-o ./glytos-csharpopenapi-generator-cli generate \
-i https://api.glytos.com/api/v1/openapi.json \
-g ruby \
-o ./glytos-rubyJust call it
The API is small enough that a generated client is often more machinery than you need. A bearer header and JSON is the whole protocol - see Authentication for the same call in eight languages.
PHP and Laravel
There is no hand-written PHP SDK, and you do not need one - Laravel's HTTP client is a better fit than a generated one.
// config/services.php
'glytos' => [
'key' => env('GLYTOS_API_KEY'),
'base' => env('GLYTOS_API_URL', 'https://api.glytos.com/api/v1'),
'webhook_secret' => env('GLYTOS_WEBHOOK_SECRET'),
],A thin client you can bind in a service provider:
namespace App\Services;
use Illuminate\Support\Facades\Http;
use Illuminate\Http\Client\PendingRequest;
class Glytos
{
protected function client(): PendingRequest
{
return Http::withToken(config('services.glytos.key'))
->baseUrl(config('services.glytos.base'))
->acceptJson()
->timeout(30);
}
public function agents(): array
{
return $this->client()->get('workflows')->json();
}
public function call(string $agentUuid, string $toNumber, array $variables = []): array
{
return $this->client()->post('calls', [
'transport' => 'phone',
'workflow_uuid' => $agentUuid,
'to_number' => $toNumber,
'variables' => $variables,
])->throw()->json();
}
}Verifying a webhook in Laravel
The signature is an HMAC-SHA256 over "{timestamp}.{raw body}". Verify it against the
raw body - $request->all() has already been parsed, and re-serialising changes
the bytes:
public function handle(Request $request)
{
$header = $request->header('X-Glytos-Signature', '');
parse_str(str_replace(',', '&', $header), $parts); // t=...,v1=...
$timestamp = $parts['t'] ?? '';
$signature = $parts['v1'] ?? '';
// Reject anything old, or a captured delivery can be replayed at you later.
if (abs(time() - (int) $timestamp) > 300) {
abort(400, 'Stale signature');
}
$expected = hash_hmac(
'sha256',
$timestamp . '.' . $request->getContent(), // raw body, not $request->all()
config('services.glytos.webhook_secret')
);
if (! hash_equals($expected, $signature)) {
abort(400, 'Bad signature');
}
ProcessGlytosEvent::dispatch($request->json()->all()); // queue it, return fast
return response()->noContent();
}See Webhooks for the event catalog.