clientId); $url .= '&response_type=code'; $url .= '&redirect_uri=' . urlencode(route('redirectURI')); //$url .= '&redirect_uri=' . urlencode('https://app.example.com/calendly/redirect-code/'); return $url; } public function authorize($code) { $tokenUrl = 'https://auth.calendly.com/oauth/token'; $client = new Client(); try { $response = $client->post($tokenUrl, [ 'form_params' => [ 'grant_type' => 'authorization_code', 'client_id' => $this->clientId, 'client_secret' => $this->clientSecret, 'redirect_uri' => route("redirectURI"), //'redirect_uri' => 'https://app.example.com/calendly/redirect-code/', 'code' => $code, ], 'headers' => [ 'Content-Type' => 'application/x-www-form-urlencoded', ], ]); $data = json_decode($response->getBody()->getContents(), true); Log::info('Info from function authorize(): ', $data); $setting = Setting::find(1); $setting->calendly_access_token = $data['access_token']; $setting->calendly_refresh_token = $data['refresh_token']; $setting->save(); Cache::forget('calendly_access_token'); Cache::put('calendly_access_token', $data['access_token'], now()->addSeconds($data['expires_in'])); return [ 'access_token' => $data['access_token'], 'refresh_token' => $data['refresh_token'], 'token_type' => $data['token_type'], 'expires_in' => $data['expires_in'] ]; } catch (\Exception $e) { throw $e; } } public function accessToken() { if (Cache::has('calendly_access_token')) { return Cache::get('calendly_access_token'); } $setting = Setting::find(1); $tokenUrl = 'https://auth.calendly.com/oauth/token'; $client = new Client(); $response = $client->post($tokenUrl, [ 'form_params' => [ 'grant_type' => 'refresh_token', 'client_id' => $this->clientId, 'client_secret' => $this->clientSecret, 'refresh_token' => $setting->calendly_refresh_token, ], 'headers' => [ 'Content-Type' => 'application/x-www-form-urlencoded', ], ]); // Decode the response $data = json_decode($response->getBody()->getContents(), true); Log::info('Info from function accessToken(): ', $data); // Store the new access token and refresh token in cache Cache::put('calendly_access_token', $data['access_token'], now()->addSeconds($data['expires_in'])); return $data['access_token']; } public function getUserUri() { // 1. Call the /users/me API to get user information $client = new Client(); try { $response = $client->request('GET', 'https://api.calendly.com/users/me', [ 'headers' => [ 'Authorization' => 'Bearer ' . $this->accessToken(), 'Content-Type' => 'application/json', ] ]); $data = json_decode($response->getBody(), true); return $userUri = $data['resource']['uri']; } catch (\Exception $e) { return false; } } public function getUserSlug() { // 1. Call the /users/me API to get user information $client = new Client(); try { $response = $client->request('GET', 'https://api.calendly.com/users/me', [ 'headers' => [ 'Authorization' => 'Bearer ' . $this->accessToken(), 'Content-Type' => 'application/json', ] ]); $data = json_decode($response->getBody(), true); return $userUri = $data['resource']['slug']; } catch (\Exception $e) { return false; } } public function eventTypes() { // 1. Call the /users/me API to get user information $client = new Client(); $responseEvent = $client->request('GET', 'https://api.calendly.com/event_types?user=' . $this->getUserUri(), [ 'headers' => [ 'Authorization' => 'Bearer ' . $this->accessToken(), 'Content-Type' => 'application/json', ] ]); $dataEvent = json_decode($responseEvent->getBody(), true); return $dataEvent['collection']; } public function setEventUri($even_type_url) { $setting = Setting::find(1); $setting->event_type = $even_type_url; $setting->save(); } public function resetEventUri() { $setting = Setting::find(1); $setting->event_type = null; $setting->calendly_access_token = null; $setting->calendly_refresh_token = null; $setting->save(); } function mapTimezone($tz){ $timezone_maping = [ "PST"=> "America/Los_Angeles", "EST"=> "America/New_York", "CST"=> "America/Chicago", "MST"=> "America/Denver", "PST"=> "America/Los_Angeles", "AST"=> "America/Halifax", ]; return data_get($timezone_maping, $tz, $tz); } function getAvailableDates($even_type_url, $month, $tz = "UTC"){ $user_slug = $this->getUserSlug(); //https://calendly.com/api/booking/event_types/lookup?event_type_slug=15-minute&profile_slug=vini-peptidewebmd //https://api.calendly.com/event_types/527074d7-c194-419a-9575-60de51220a8e/calendar/range?timezone=America/Chicago&diagnostics=false&range_start=2024-10-01&range_end=2024-10-31&scheduling_link_uuid=cmm8-rtf-7q6 //https://calendly.com/api/booking/event_types/527074d7-c194-419a-9575-60de51220a8e/calendar/range?timezone=Asia%2FKarachi&diagnostics=false&range_start=2024-10-26&range_end=2024-10-31&scheduling_link_uuid=cmm8-rtf-7q6 // $user_slug = explode('/', $userUri)[4]; $client = new Client(); $response = $client->request('GET', $even_type_url, [ 'headers' => [ 'Authorization' => 'Bearer ' . $this->accessToken(), 'Content-Type' => 'application/json', ], // 'query' => $queryParams ]); $event = json_decode($response->getBody(), true); $web_event = json_decode($this->makeRequest("https://calendly.com/api/booking/event_types/lookup?event_type_slug={$event['resource']['slug']}&profile_slug={$user_slug}"),true); // var_Dump("https://calendly.com/api/booking/event_types/lookup?event_type_slug={$event['resource']['slug']}&profile_slug={$user_slug}"); $event_slug = data_get($web_event,"uuid"); // $eventDetails = json_decode($this->makeRequest($eventDetailsUrl)); // $eventDetailsUrl = "https://calendly.com/api/booking/event_types/lookup?event_type_slug=$event_type&profile_slug=$owner_id"; $current_month = Carbon::now()->month; $current_date = Carbon::now()->day; $timezone = $this->mapTimezone($tz); // if ($month == $current_month && $current_date > 15) {} $date = Carbon::createFromDate(Carbon::now()->year, $month, 1); // $start_date = Carbon::now()->startOfMonth()->tz("UTC"); $start_date = $date->startOfMonth()->format('Y-m-d'); $end_date = $date->endOfMonth()->format('Y-m-d'); $uid = data_get($web_event,"scheduling_link.uid"); $url = "https://calendly.com/api/booking/event_types/{$event_slug}/calendar/range?timezone=$timezone&diagnostics=false&range_start=$start_date&range_end=$end_date&scheduling_link_uuid={$uid}"; $response = $client->request('GET', $url, [ 'headers' => [ 'Authorization' => 'Bearer ' . $this->accessToken(), 'Content-Type' => 'application/json', ], ]); $eventDetails = json_decode($this->makeRequest($url),true); $availableSlots = []; foreach ($eventDetails['days'] as $_event) { if($_event['status'] == 'available') { $slots = [ // 'date' => $event['date'], ]; foreach ($_event['spots'] as $slot) { if($slot['status'] == 'available'){ $slotDateTime = Carbon::parse($slot['start_time'])->tz($timezone); $slot['formatted_datetime'] = $slotDateTime->format('Y-m-d g:i:00'); $slot['scheduling_url'] = "https://calendly.com/$user_slug/{$event['resource']['slug']}/{$slot['start_time']}"; } $slots[] = $slot; } $availableSlots[$_event['date']] = $slots; } } // var_dump($eventDetails); return $availableSlots; } function getAvailableDatesOld($even_type_url, $month, $tz = "UTC") { $cacheKey = $even_type_url . $month . $tz; return Cache::remember($cacheKey, now()->addMinutes(2), function () use ($even_type_url, $month, $tz) { return $this->getAvailableDates2($even_type_url, $month, $tz); }); } function getAvailableDates2($even_type_url, $month, $tz = "UTC") { try { $availableTimes = []; $date = Carbon::createFromDate(Carbon::now()->year, $month, 1, $tz); $date = $date->startOfMonth()->tz("UTC"); $endMonthDate = Carbon::createFromDate(Carbon::now()->year, $month, 1, $tz); $endMonthDate = $endMonthDate->endOfMonth()->tz("UTC"); while ($date < $endMonthDate) { $start_time = $date->startOfDay()->format('Y-m-d\T24:00:00.000000\Z'); $end_time = $date->addDays(7)->endOfDay()->format('Y-m-d\T24:00:00.000000\Z'); $client = new Client(); try { // Prepare API endpoint with the required parameters $eventTypeUrl = 'https://api.calendly.com/event_type_available_times'; $queryParams = [ 'event_type' => $even_type_url, 'start_time' => $start_time, 'end_time' => $end_time ]; // dd($queryParams); $str = "event_type=" . urlencode($queryParams['event_type']) . "&" . "start_time=" . urlencode($queryParams['start_time']) . "&" . "end_time=" . urlencode($queryParams['end_time']); $eventTypeUrl = $eventTypeUrl . "?" . ($str); // Send the request to Calendly $response = $client->request('GET', $eventTypeUrl, [ 'headers' => [ 'Authorization' => 'Bearer ' . $this->accessToken(), 'Content-Type' => 'application/json', ], // 'query' => $queryParams ]); $data = json_decode($response->getBody(), true); //$availableTimes += $data['collection']; foreach ($data['collection'] as $slot) { $slotDate = Carbon::parse($slot['start_time'])->tz($tz)->format('Y-m-d'); if (!isset($availableTimes[$slotDate])) { $availableTimes[$slotDate] = []; } $slotDateTime = Carbon::parse($slot['start_time'])->tz($tz); $dateKey = $slotDateTime->format('Y-m-d'); $slot['formatted_datetime'] = $slotDateTime->format('Y-m-d g:i:00'); $availableTimes[$slotDate][] = $slot; } } catch (Exception $e) { Log::error('Error from function getAvailableDates(): ' . $e->getMessage(), [ 'eventTypeUrl' => $eventTypeUrl, 'queryParams' => $queryParams, 'full_rul' => $eventTypeUrl, 'Authorization' => 'Bearer ' . $this->accessToken(), ]); continue; } $date->addSecond(); } return $availableTimes; } catch (\Exception $e) { return response()->json(['error' => 'Failed to fetch available times: ' . $e->getMessage()], 500); } } // write function to do php get and post request and add json support function makeRequest($url, $method = 'GET', $data = [], $headers = [], $json = false, $proxy = "iproyal15202:pb86ljih495_country-us@geo.iproyal.com:12321") { $ch = curl_init($url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_ENCODING, '',); if ($proxy) { curl_setopt($ch, CURLOPT_PROXY, 'http://geo.iproyal.com:12321'); // Set the proxy address and port curl_setopt($ch, CURLOPT_PROXYUSERPWD, 'iproyal15202:Pb86ljiH495_country-us'); // Set the proxy authentication credentials } $headers = ['User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36', ...$headers]; if ($method === 'POST') { if ($json) { $headers = ['Content-Type: application/json', ...$headers]; curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST'); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data)); } else { curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data)); } } if (!empty($headers)) { curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); } $response = curl_exec($ch); curl_close($ch); return $response; } function getCrfToken($url) { try { $response = $this->makeRequest($url); preg_match('//', $response, $matches); return $matches[1]; } catch (Exception $e) { $response = $this->makeRequest($url); preg_match('//', $response, $matches); return $matches[1]; } } function getEventDetails($url) { $response = $this->makeRequest($url); return $response; } //random string function function generateRandomString($length = 10) { $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; $randomString = ''; for ($i = 0; $i < $length; $i++) { $randomString .= $characters[rand(0, strlen($characters) - 1)]; } return $randomString; } public function bookEvent($url, $name, $email, $timezone = "UTC") { $url_parts = explode("/", $url); $bookingDate = $url_parts[5]; $event_type = $url_parts[4]; $owner_id = $url_parts[3]; $eventDetailsUrl = "https://calendly.com/api/booking/event_types/lookup?event_type_slug=$event_type&profile_slug=$owner_id"; $eventDetails = json_decode($this->makeRequest($eventDetailsUrl)); // var_dump($eventDetails); $crfToken = $this->getCrfToken($url); $timezone = $this->mapTimezone($timezone); // $eventUuid = $eventDetails->uuid; $eventUuid = data_get($eventDetails, 'eventDetails.uid'); $link_uuid = data_get($eventDetails, 'scheduling_link.uid'); // $custom_fields_id = $eventDetails->custom_fields[0]->id; $custom_fields_id = data_get($eventDetails, 'custom_fields.0.id'); $booking_request_id = urlencode($this->generateRandomString(36) . "|$bookingDate|$eventUuid|$name"); //convert to php array $bookingData = [ "analytics" => [ //php date with 10 sec gap "invitee_landed_at" => date("Y-m-d\TH:i:s.uP", strtotime($bookingDate) - 200), "browser" => "Chrome 129", "device" => "undefined Mac OS X 10.15.7", "fields_filled" => 1, "fields_presented" => 1, "booking_flow" => "v3", "seconds_to_convert" => 200 ], "embed" => (object)[], "event" => [ "start_time" => $bookingDate, "location_configuration" => data_get($eventDetails,"location_configurations.0",[ "location" => "", "phone_number" => "", "additional_info" => "" ]), "guests" => [] ], "event_fields" => [ [ "id" => $custom_fields_id, "name" => "Please share anything that will help prepare for our meeting.", "format" => "text", "required" => false, "position" => 0, "answer_choices" => null, "include_other" => false, "value" => "" ] ], "invitee" => [ "timezone" => $timezone, "time_notation" => "24h", "full_name" => $name, "email" => $email ], "payment_token" => (object)[], "tracking" => [ "fingerprint" => $this->generateRandomString(32) ], "scheduling_link_uuid" => $link_uuid, "locale" => "en", "verification_code" => null, "remember_device" => false ]; $response = $this->makeRequest("https://calendly.com/api/booking/invitees", 'POST', $bookingData, [ 'x-csrf-token: ' . $crfToken, 'x-page-rendered-at: ' . date('Y-m-d\TH:i:s'), 'x-requested-with: XMLHttpRequest', 'referer: ' . $url, "booking-request-id: $booking_request_id" ], true); return $response; } }