get('/bird/voice/calls/log', function () { ScopeMiddleware::requireScope(Scope::SUPERUSER_READ, '/bird/voice/calls/log'); global $response; $this->requirePermission('modules_bird_voice_calls_log_list'); $client = new bird(); $workspaceId = $this->birdResolveWorkspaceId($client); $query = $this->birdPayloadWithout(['workspaceId', 'channelId']); $query = $this->birdNormalizeCsvField($query, 'channelId'); $query = $this->birdNormalizeCsvField($query, 'tag'); $query = $this->birdValidateSchema($query, bird_request_schemas::voiceCallsLogQuery()); $query = bird_voice_calls_log_query_payload::fromArray($query)->toArray(); $res = $client->getVoiceCallsLog($workspaceId, $query); $response->success($res ?? []); }, [ 'modules_bird_voice_calls_log_list' => 'List voice call log entries via Bird', ]); // Create a voice call $this->post('/bird/voice/calls', function () { global $response; $this->requirePermission('modules_bird_voice_calls_create'); $client = new bird(); [$workspaceId, $channelId] = $this->birdResolveWorkspaceAndChannelIds($client); $payload = $this->birdPayloadWithout(['workspaceId', 'channelId']); $payload = $this->birdValidateSchema($payload, bird_request_schemas::voiceCreateCallBody()); $payload = bird_voice_create_call_payload::fromArray($payload)->toArray(); $res = $client->createVoiceCall($workspaceId, $channelId, $payload); $response->success($res ?? ['status' => 'ok']); }, [ 'modules_bird_voice_calls_create' => 'Create/place a voice call via Bird', ]); // List voice calls $this->get('/bird/voice/calls', function () { global $response; $this->requirePermission('modules_bird_voice_calls_list'); $client = new bird(); [$workspaceId, $channelId] = $this->birdResolveWorkspaceAndChannelIds($client); $query = $this->birdPayloadWithout(['workspaceId', 'channelId']); $query = $this->birdNormalizeCsvField($query, 'tag'); $query = $this->birdValidateSchema($query, bird_request_schemas::voiceListCallsQuery()); $query = bird_voice_list_calls_query_payload::fromArray($query)->toArray(); $res = $client->listVoiceCalls($workspaceId, $channelId, $query); $response->success($res ?? []); }, [ 'modules_bird_voice_calls_list' => 'List voice calls via Bird', ]); // Get a voice call by ID $this->get('/bird/voice/calls/{id}', function () { global $response; $this->requirePermission('modules_bird_voice_calls_get'); $client = new bird(); [$workspaceId, $channelId] = $this->birdResolveWorkspaceAndChannelIds($client); $callId = $this->birdResolveRouteCallId(); $res = $client->getVoiceCall($workspaceId, $channelId, $callId); $response->success($res ?? []); }, [ 'modules_bird_voice_calls_get' => 'Get a voice call by ID via Bird', ]); // Update a voice call by ID $this->patch('/bird/voice/calls/{id}', function () { global $response; $this->requirePermission('modules_bird_voice_calls_update'); $client = new bird(); [$workspaceId, $channelId] = $this->birdResolveWorkspaceAndChannelIds($client); $callId = $this->birdResolveRouteCallId(); $payload = $this->birdPayloadWithout(['workspaceId', 'channelId']); $payload = $this->birdValidateSchema($payload, bird_request_schemas::voiceUpdateCallBody()); $payload = bird_voice_update_call_payload::fromArray($payload)->toArray(); $res = $client->updateVoiceCall($workspaceId, $channelId, $callId, $payload); $response->success($res ?? ['status' => 'ok']); }, [ 'modules_bird_voice_calls_update' => 'Update a voice call by ID via Bird', ]); // Answer an incoming call by ID $this->post('/bird/voice/calls/{id}/answer', function () { global $response; $this->requirePermission('modules_bird_voice_calls_answer'); $client = new bird(); [$workspaceId, $channelId] = $this->birdResolveWorkspaceAndChannelIds($client); $callId = $this->birdResolveRouteCallId(); $payload = $this->birdPayloadWithout(['workspaceId', 'channelId']); $payload = $this->birdValidateSchema($payload, bird_request_schemas::noBody()); $payload = bird_no_body_payload::fromArray($payload)->toArray(); $res = $client->answerVoiceCall($workspaceId, $channelId, $callId, $payload); $response->success($res ?? ['status' => 'ok']); }, [ 'modules_bird_voice_calls_answer' => 'Answer a voice call by ID via Bird', ]); // Mark call as ringing by ID $this->post('/bird/voice/calls/{id}/ringing', function () { global $response; $this->requirePermission('modules_bird_voice_calls_ringing'); $client = new bird(); [$workspaceId, $channelId] = $this->birdResolveWorkspaceAndChannelIds($client); $callId = $this->birdResolveRouteCallId(); $payload = $this->birdPayloadWithout(['workspaceId', 'channelId']); $payload = $this->birdValidateSchema($payload, bird_request_schemas::noBody()); $payload = bird_no_body_payload::fromArray($payload)->toArray(); $res = $client->ringVoiceCall($workspaceId, $channelId, $callId, $payload); $response->success($res ?? ['status' => 'ok']); }, [ 'modules_bird_voice_calls_ringing' => 'Mark a voice call as ringing via Bird', ]); // Hang up an active call by ID $this->post('/bird/voice/calls/{id}/hangup', function () { global $response; $this->requirePermission('modules_bird_voice_calls_hangup'); $client = new bird(); [$workspaceId, $channelId] = $this->birdResolveWorkspaceAndChannelIds($client); $callId = $this->birdResolveRouteCallId(); $payload = $this->birdPayloadWithout(['workspaceId', 'channelId']); $payload = $this->birdValidateSchema($payload, bird_request_schemas::voiceHangupBody()); $payload = bird_voice_hangup_payload::fromArray($payload)->toArray(); $res = $client->hangupVoiceCall($workspaceId, $channelId, $callId, $payload); $response->success($res ?? ['status' => 'ok']); }, [ 'modules_bird_voice_calls_hangup' => 'Hang up a voice call by ID via Bird', ]); // Playback media on an active call by ID $this->post('/bird/voice/calls/{id}/playback', function () { global $response; $this->requirePermission('modules_bird_voice_calls_playback'); $client = new bird(); [$workspaceId, $channelId] = $this->birdResolveWorkspaceAndChannelIds($client); $callId = $this->birdResolveRouteCallId(); $payload = $this->birdPayloadWithout(['workspaceId', 'channelId']); $payload = $this->birdValidateSchema($payload, bird_request_schemas::voicePlaybackBody()); $payload = bird_voice_playback_payload::fromArray($payload)->toArray(); $res = $client->playbackVoiceCall($workspaceId, $channelId, $callId, $payload); $response->success($res ?? ['status' => 'ok']); }, [ 'modules_bird_voice_calls_playback' => 'Playback media on a voice call by ID via Bird', ]); // Say a message on an active call $this->post('/bird/voice/calls/{id}/say', function () { global $response; $this->requirePermission('modules_bird_voice_calls_say'); $client = new bird(); [$workspaceId, $channelId] = $this->birdResolveWorkspaceAndChannelIds($client); $callId = $this->birdResolveRouteCallId(); $payload = $this->birdPayloadWithout(['workspaceId', 'channelId']); $payload = $this->birdValidateSchema($payload, bird_request_schemas::voiceSayBody()); $payload = bird_voice_say_payload::fromArray($payload)->toArray(); $res = $client->sayMessage($workspaceId, $channelId, $callId, $payload); $response->success($res ?? ['status' => 'ok']); }, [ 'modules_bird_voice_calls_say' => 'Say a message on a voice call by ID via Bird', ]); // Gather input on an active call $this->post('/bird/voice/calls/{id}/gather', function () { global $response; $this->requirePermission('modules_bird_voice_calls_gather'); $client = new bird(); [$workspaceId, $channelId] = $this->birdResolveWorkspaceAndChannelIds($client); $callId = $this->birdResolveRouteCallId(); $payload = $this->birdPayloadWithout(['workspaceId', 'channelId']); $payload = $this->birdValidateSchema($payload, bird_request_schemas::voiceGatherBody()); $payload = bird_voice_gather_payload::fromArray($payload)->toArray(); $res = $client->gatherMessage($workspaceId, $channelId, $callId, $payload); $response->success($res ?? ['status' => 'ok']); }, [ 'modules_bird_voice_calls_gather' => 'Gather input on a voice call by ID via Bird', ]); // Bridge current call to another destination $this->post('/bird/voice/calls/{id}/bridge', function () { global $response; $this->requirePermission('modules_bird_voice_calls_bridge'); $client = new bird(); [$workspaceId, $channelId] = $this->birdResolveWorkspaceAndChannelIds($client); $callId = $this->birdResolveRouteCallId(); $payload = $this->birdPayloadWithout(['workspaceId', 'channelId']); $payload = $this->birdValidateSchema($payload, bird_request_schemas::voiceBridgeBody()); $payload = bird_voice_bridge_payload::fromArray($payload)->toArray(); $res = $client->bridgeVoiceCall($workspaceId, $channelId, $callId, $payload); $response->success($res ?? ['status' => 'ok']); }, [ 'modules_bird_voice_calls_bridge' => 'Bridge a voice call by ID via Bird', ]); // Record call command endpoint $this->post('/bird/voice/calls/{id}/record', function () { global $response; $this->requirePermission('modules_bird_voice_calls_record'); $client = new bird(); [$workspaceId, $channelId] = $this->birdResolveWorkspaceAndChannelIds($client); $callId = $this->birdResolveRouteCallId(); $payload = $this->birdPayloadWithout(['workspaceId', 'channelId']); $payload = $this->birdValidateSchema($payload, bird_request_schemas::voiceRecordBody()); $payload = bird_voice_record_payload::fromArray($payload)->toArray(); $res = $client->recordVoiceCall($workspaceId, $channelId, $callId, $payload); $response->success($res ?? ['status' => 'ok']); }, [ 'modules_bird_voice_calls_record' => 'Record a voice call by ID via Bird', ]); // Start call recording session $this->post('/bird/voice/calls/{id}/recordings', function () { global $response; $this->requirePermission('modules_bird_voice_calls_recordings_create'); $client = new bird(); [$workspaceId, $channelId] = $this->birdResolveWorkspaceAndChannelIds($client); $callId = $this->birdResolveRouteCallId(); $payload = $this->birdPayloadWithout(['workspaceId', 'channelId']); $payload = $this->birdValidateSchema($payload, bird_request_schemas::voiceRecordingsCreateBody()); $payload = bird_voice_recordings_create_payload::fromArray($payload)->toArray(); $res = $client->createVoiceCallRecordingSession($workspaceId, $channelId, $callId, $payload); $response->success($res ?? ['status' => 'ok']); }, [ 'modules_bird_voice_calls_recordings_create' => 'Create a voice call recording session via Bird', ]); // List call recordings $this->get('/bird/voice/calls/{id}/recordings', function () { global $response; $this->requirePermission('modules_bird_voice_calls_recordings_list'); $client = new bird(); [$workspaceId, $channelId] = $this->birdResolveWorkspaceAndChannelIds($client); $callId = $this->birdResolveRouteCallId(); $query = $this->birdPayloadWithout(['workspaceId', 'channelId']); $query = $this->birdValidateSchema($query, bird_request_schemas::voiceRecordingsListQuery()); $query = bird_voice_recordings_list_query_payload::fromArray($query)->toArray(); $res = $client->listVoiceCallRecordings($workspaceId, $channelId, $callId, $query); $response->success($res ?? []); }, [ 'modules_bird_voice_calls_recordings_list' => 'List voice call recordings via Bird', ]); // Get single call recording $this->get('/bird/voice/calls/{id}/recordings/{recordingId}', function () { global $response; $this->requirePermission('modules_bird_voice_calls_recordings_get'); $client = new bird(); [$workspaceId, $channelId] = $this->birdResolveWorkspaceAndChannelIds($client); $callId = $this->birdResolveRouteCallId(); $recordingId = $this->birdResolveRouteRecordingId(); $res = $client->getVoiceCallRecording($workspaceId, $channelId, $callId, $recordingId); $response->success($res ?? []); }, [ 'modules_bird_voice_calls_recordings_get' => 'Get a voice call recording by ID via Bird', ]); // Update single call recording $this->patch('/bird/voice/calls/{id}/recordings/{recordingId}', function () { global $response; $this->requirePermission('modules_bird_voice_calls_recordings_update'); $client = new bird(); [$workspaceId, $channelId] = $this->birdResolveWorkspaceAndChannelIds($client); $callId = $this->birdResolveRouteCallId(); $recordingId = $this->birdResolveRouteRecordingId(); $payload = $this->birdPayloadWithout(['workspaceId', 'channelId']); $payload = $this->birdValidateSchema($payload, bird_request_schemas::voiceRecordingUpdateBody()); $payload = bird_voice_recording_update_payload::fromArray($payload)->toArray(); $res = $client->updateVoiceCallRecording($workspaceId, $channelId, $callId, $recordingId, $payload); $response->success($res ?? ['status' => 'ok']); }, [ 'modules_bird_voice_calls_recordings_update' => 'Update a voice call recording via Bird', ]); // Get call insights $this->get('/bird/voice/calls/{id}/insights', function () { global $response; $this->requirePermission('modules_bird_voice_calls_insights_get'); $client = new bird(); [$workspaceId, $channelId] = $this->birdResolveWorkspaceAndChannelIds($client); $callId = $this->birdResolveRouteCallId(); $res = $client->getVoiceCallInsights($workspaceId, $channelId, $callId); $response->success($res ?? []); }, [ 'modules_bird_voice_calls_insights_get' => 'Get voice call insights by call ID via Bird', ]); // Place test outbound call and hang up when accepted $this->post('/bird/voice/calls/test-outbound', function () { global $response; $this->requirePermission('modules_bird_voice_calls_test_outbound'); $client = new bird(); [$workspaceId, $channelId] = $this->birdResolveWorkspaceAndChannelIds($client); $payload = $this->birdPayloadWithout(['workspaceId', 'channelId']); $payload = $this->birdValidateSchema($payload, bird_request_schemas::voiceTestOutboundBody()); $payload = bird_voice_test_outbound_payload::fromArray($payload)->toArray(); try { $result = $client->createOutboundTestCallAndHangupWhenAccepted($workspaceId, $channelId, $payload); $response->success($result); } catch (\Throwable $e) { $response->error($e->getMessage(), 500); } }, [ 'modules_bird_voice_calls_test_outbound' => 'Place a test outbound call and hang up when accepted', ]); } }