PHP SDK
A PSR-compliant PHP client for the IdentityCall API with Guzzle HTTP support.
Installation
composer require guzzlehttp/guzzleQuick Start
<?php
require 'vendor/autoload.php';
require 'IdentityCallClient.php';
use IdentityCall\Client;
$client = new Client();
// List recordings
$result = $client->recordings()->list();
foreach ($result['data'] as $recording) {
echo "{$recording['id']}: {$recording['name']}\n";
}Complete Client Implementation
Create a file called IdentityCallClient.php:
IdentityCallClient.php
<?php
namespace IdentityCall;
use GuzzleHttp\Client as GuzzleClient;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Psr7\MultipartStream;
// Exception classes
class IdentityCallException extends \Exception {
protected $statusCode;
protected $response;
public function __construct($message, $statusCode = null, $response = null) {
parent::__construct($message);
$this->statusCode = $statusCode;
$this->response = $response;
}
public function getStatusCode() {
return $this->statusCode;
}
public function getResponse() {
return $this->response;
}
}
class AuthenticationException extends IdentityCallException {}
class PermissionException extends IdentityCallException {}
class NotFoundException extends IdentityCallException {}
class ValidationException extends IdentityCallException {}
class RateLimitException extends IdentityCallException {
protected $retryAfter;
public function __construct($message, $retryAfter = 60, $statusCode = null, $response = null) {
parent::__construct($message, $statusCode, $response);
$this->retryAfter = $retryAfter;
}
public function getRetryAfter() {
return $this->retryAfter;
}
}
// Recordings resource
class Recordings {
private $client;
public function __construct(Client $client) {
$this->client = $client;
}
public function list(int $page = 1, int $perPage = 20): array {
return $this->client->request('GET', '/recordings', [
'query' => ['page' => $page, 'per_page' => $perPage]
]);
}
public function create(string $filePath, array $options = []): array {
$multipart = [
[
'name' => 'file',
'contents' => fopen($filePath, 'r'),
'filename' => $options['filename'] ?? basename($filePath)
],
[
'name' => 'language',
'contents' => $options['language'] ?? 'en'
]
];
if (isset($options['name'])) {
$multipart[] = ['name' => 'name', 'contents' => $options['name']];
}
return $this->client->request('POST', '/recordings', [
'multipart' => $multipart
]);
}
public function get(int $recordingId): array {
return $this->client->request('GET', "/recordings/{$recordingId}");
}
public function update(int $recordingId, array $data): array {
return $this->client->request('PATCH', "/recordings/{$recordingId}", [
'json' => $data
]);
}
public function delete(int $recordingId): void {
$this->client->request('DELETE', "/recordings/{$recordingId}");
}
public function transcription(int $recordingId): array {
return $this->client->request('GET', "/recordings/{$recordingId}/transcription");
}
public function results(int $recordingId): array {
return $this->client->request('GET', "/recordings/{$recordingId}/results");
}
public function summary(int $recordingId): array {
return $this->client->request('GET', "/recordings/{$recordingId}/summary");
}
public function waitForCompletion(int $recordingId, int $timeout = 600, int $pollInterval = 5): array {
$startTime = time();
while (true) {
$result = $this->get($recordingId);
$recording = $result['data'];
if ($recording['status'] === 'completed') {
return $recording;
}
if ($recording['status'] === 'failed') {
throw new IdentityCallException('Transcription failed');
}
if (time() - $startTime > $timeout) {
throw new \RuntimeException('Transcription timed out');
}
sleep($pollInterval);
}
}
}
// Main client
class Client {
private const DEFAULT_BASE_URL = 'https://api.identitycall.com/api/v1/public';
private const MAX_RETRIES = 3;
private $apiKey;
private $baseUrl;
private $httpClient;
private $recordings;
public function __construct(array $options = []) {
$this->apiKey = $options['api_key'] ?? getenv('IDENTITYCALL_API_KEY');
if (!$this->apiKey) {
throw new \InvalidArgumentException('API key is required');
}
$this->baseUrl = $options['base_url'] ?? self::DEFAULT_BASE_URL;
$this->httpClient = new GuzzleClient([
'base_uri' => $this->baseUrl,
'timeout' => $options['timeout'] ?? 30,
'headers' => [
'Authorization' => "Bearer {$this->apiKey}",
'Accept' => 'application/json'
]
]);
$this->recordings = new Recordings($this);
}
public function recordings(): Recordings {
return $this->recordings;
}
public function request(string $method, string $path, array $options = []): ?array {
$attempt = 0;
while ($attempt < self::MAX_RETRIES) {
try {
$response = $this->httpClient->request($method, $path, $options);
if ($response->getStatusCode() === 204) {
return null;
}
return json_decode($response->getBody()->getContents(), true);
} catch (RequestException $e) {
$response = $e->getResponse();
if ($response === null) {
throw $e;
}
$statusCode = $response->getStatusCode();
$data = json_decode($response->getBody()->getContents(), true) ?? [];
$errorMessage = $data['error'] ?? 'Unknown error';
// Handle rate limiting
if ($statusCode === 429 && $attempt < self::MAX_RETRIES - 1) {
$retryAfter = $data['retry_after'] ?? 60;
sleep($retryAfter);
$attempt++;
continue;
}
// Handle server errors
if ($statusCode >= 500 && $attempt < self::MAX_RETRIES - 1) {
sleep(pow(2, $attempt));
$attempt++;
continue;
}
// Throw appropriate exception
$this->throwException($statusCode, $errorMessage, $data);
}
$attempt++;
}
throw new IdentityCallException('Max retries exceeded');
}
private function throwException(int $statusCode, string $message, array $data): void {
switch ($statusCode) {
case 401:
throw new AuthenticationException($message, $statusCode, $data);
case 403:
throw new PermissionException($message, $statusCode, $data);
case 404:
throw new NotFoundException($message, $statusCode, $data);
case 422:
throw new ValidationException($message, $statusCode, $data);
case 429:
$retryAfter = $data['retry_after'] ?? 60;
throw new RateLimitException($message, $retryAfter, $statusCode, $data);
default:
throw new IdentityCallException($message, $statusCode, $data);
}
}
}Usage Examples
List Recordings
<?php
use IdentityCall\Client;
$client = new Client();
// Get first page
$result = $client->recordings()->list();
foreach ($result['data'] as $recording) {
echo "[{$recording['id']}] {$recording['name']} - {$recording['status']}\n";
}
// With pagination
$result = $client->recordings()->list(2, 50);
$meta = $result['meta'];
echo "Page {$meta['current_page']} of {$meta['total_pages']}\n";Upload Recording
<?php
$result = $client->recordings()->create('/path/to/call.mp3', [
'language' => 'en',
'name' => 'Customer Support Call'
]);
$recordingId = $result['data']['id'];
echo "Uploaded! Recording ID: {$recordingId}\n";Wait for Transcription
<?php
// Upload
$result = $client->recordings()->create('/path/to/call.mp3');
$recordingId = $result['data']['id'];
// Wait for completion
echo "Processing...\n";
$recording = $client->recordings()->waitForCompletion($recordingId);
echo "Completed! Duration: {$recording['duration_ms']}ms\n";
// Get transcription
$transcription = $client->recordings()->transcription($recordingId);
echo $transcription['data']['full_text'];Get Analysis Results
<?php
$results = $client->recordings()->results($recordingId);
// Goals
echo "Goals:\n";
foreach ($results['data']['goals'] as $goal) {
$status = $goal['met'] ? '✓' : '✗';
$score = number_format($goal['score'], 2);
echo " {$status} {$goal['goal_name']}: {$score}\n";
}
// Keywords
echo "\nKeywords:\n";
foreach ($results['data']['keywords'] as $kw) {
echo " \"{$kw['keyword_name']}\" - {$kw['count']} mentions\n";
}Error Handling
<?php
use IdentityCall\Client;
use IdentityCall\AuthenticationException;
use IdentityCall\PermissionException;
use IdentityCall\NotFoundException;
use IdentityCall\RateLimitException;
$client = new Client();
try {
$recording = $client->recordings()->get(999999);
} catch (NotFoundException $e) {
echo "Recording not found\n";
} catch (PermissionException $e) {
echo "Permission denied\n";
} catch (AuthenticationException $e) {
echo "Invalid API key\n";
} catch (RateLimitException $e) {
echo "Rate limited. Retry in {$e->getRetryAfter()} seconds\n";
}Iterate All Pages
<?php
function getAllRecordings(Client $client): array {
$allRecordings = [];
$page = 1;
$perPage = 100;
while (true) {
$result = $client->recordings()->list($page, $perPage);
$allRecordings = array_merge($allRecordings, $result['data']);
$meta = $result['meta'];
if ($meta['current_page'] >= $meta['total_pages']) {
break;
}
$page++;
}
return $allRecordings;
}
// Usage
$recordings = getAllRecordings($client);
echo "Total recordings: " . count($recordings) . "\n";Laravel Integration
For Laravel projects, create a service provider:
app/Providers/IdentityCallServiceProvider.php
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use IdentityCall\Client;
class IdentityCallServiceProvider extends ServiceProvider
{
public function register(): void
{
$this->app->singleton(Client::class, function ($app) {
return new Client([
'api_key' => config('services.identitycall.api_key'),
'base_url' => config('services.identitycall.base_url'),
]);
});
}
}Add configuration:
config/services.php
<?php
return [
// ...
'identitycall' => [
'api_key' => env('IDENTITYCALL_API_KEY'),
'base_url' => env('IDENTITYCALL_BASE_URL', 'https://api.identitycall.com/api/v1/public'),
],
];Use in controllers:
<?php
namespace App\Http\Controllers;
use IdentityCall\Client;
class RecordingController extends Controller
{
public function __construct(
private Client $identityCall
) {}
public function index()
{
$result = $this->identityCall->recordings()->list();
return view('recordings.index', ['recordings' => $result['data']]);
}
}