I know there are many requests about this issue; but none of them seems to answer my question. To automate the generation of Google Calendar appointments, including the automatic generation of an according Google Meet Link, I’ve done the following:
- Created Google Cloud Project
- Enabled Google Calendar API for concerned account
- Created New Google Service Account
- Grabbed the e-mail address of that service account, and added it under the Google Calendar’s Settings, to allow for the privileges Make changes / Manage access for that e-mail.
- downloaded the most recent version of the google api client (https://packagist.org/packages/google/apiclient).
- Went to Google Service Accounts > Keys > Generated new key file as
JSON
, let’s sayaccess.json
. - Implement code for generation of calendar API appointment, including recent patches (https://developers.google.com/calendar/api/releases?hl=de#september_07_2020), within PHP:
putenv('GOOGLE_APPLICATION_CREDENTIALS=my/key/data/directoy/access.json');
$client = new Client();
$client->useApplicationDefaultCredentials();
$client->addScope(Google_Service_Calendar::CALENDAR);
$client->setSubject("{address_explained_below}");
// Set up the Calendar API service
$service = new Google_Service_Calendar($client);
// Create a new event on Google Calendar
$event = new Google_Service_Calendar_Event(
[
'summary' => 'Meeting',
'start' => [
'dateTime' => '2023-04-07T10:00:00-07:00',
// Replace with your desired start time
'timeZone' => 'America/Los_Angeles',
// Replace with your desired timezone
],
'end' => [
'dateTime' => '2023-04-07T11:00:00-07:00',
// Replace with your desired end time
'timeZone' => 'America/Los_Angeles',
// Replace with your desired timezone
]
]
);
// Set the event's conference data to use Google Meet
$conferenceRequest = new Google_Service_Calendar_CreateConferenceRequest();
$conferenceRequest->setRequestId(uniqid());
$solution_key = new Google_Service_Calendar_ConferenceSolutionKey();
$solution_key->setType("hangoutsMeet");
$conferenceRequest->setConferenceSolutionKey($solution_key);
$conference = new Google_Service_Calendar_ConferenceData();
$conference->setCreateRequest($conferenceRequest);
$event->setConferenceData($conference);
// Insert the event into the user's calendar
$calendarId = 'myCalendarsID';
$event = $service->events->insert(
$calendarId,
$event,
[ 'conferenceDataVersion' => 1 ]
);
var_dump($event);
// Retrieve the generated Google Meet link from the event's conference data
$meetLink = $event->getHangoutLink();
I’ve really tried to follow the advices of all of the other posts regarding this issue in this forum; but nothing did the trick, and I am getting now a 400 Bad Request
error, no matter the type
I set (hangoutsMeet
or whatever else), saying Invalid conference type value.
. What am I missing? I’ve come across this; is this maybe library-specific, and it’s rather better to implement raw HTTP REST API calls, without using the library?
Update:
After using the Test Feature provided by Google to fire this request here:
GET https://www.googleapis.com/calendar/v3/calendars/{calendarId}
I can indeed confirm that hangoutsMeet
is within the allowedConferenceSolutionTypes
.
{
"kind": "calendar#calendar",
"etag": "secret",
"id": "secret",
"summary": "secret",
"timeZone": "secret",
"conferenceProperties": {
"allowedConferenceSolutionTypes": [
"hangoutsMeet"
]
}
}
So I suppose, according to @Lorena Gomez (Thanks!) comment, that I have to "grant domain-wide delegation to my service account and impersonate the user with rights to that calendar", even though I’m not really clear on what that actually means / does.
Regarding the domain-wide delegation, I’ve now done that for the registered service account, as specified here. This seems to have worked, although I cannot see any difference in the service account panel within the "IAM and Management" Screen under the concerned service account. Does this delegation may take some time to have an effect?
I’ve been digging further and apparently this line of code here:
$client->setSubject($user_to_impersonate);
serves to impersonate the user with rights to that calendar. But what should be the value of $user_to_impersonate
here? I’ve provided the e-mail address of the service account for which I granted domain-wide delegation for the https://www.googleapis.com/auth/calendar
scope, in which case I still get:
Google_Service_Exception: {
"error": {
"errors": [
{
"domain": "global",
"reason": "invalid",
"message": "Invalid conference type value."
}
],
"code": 400,
"message": "Invalid conference type value."
}
}
Then I’ve tried it with the e-mail address of the google account that actually owns the calendar, which resulted in:
Google_Service_Exception: {
"error": "unauthorized_client",
"error_description": "Client is unauthorized to retrieve access tokens using this method, or client not authorized for any of the scopes requested."
}
Error code: 401
I’ve then tried it with the user ID of the service account which was granted domain-wide delegation, which is when I get:
Caught Google_Service_Exception: {
"error": "invalid_request",
"error_description": "Invalid principal"
}
Error code: 400
So I don’t understand, what am I still missing? I’ve updated my code above to the state as it is now (The string address_explained_below
is replaced with the three above-mentioned attempts).
I’ve now made a last attempt where I’ve created a new service account, enabled the domain-wide delegation for it, generated the access keys, and uploaded them to the server. When then running the code above with the e-mail address of that newly created service account, I got a 404 Not found
error. I then went to the Google Calendar Settings of the concerned calendar, and added the e-mail address of the service account under Share with specific people or groups
(I’ve translated that part; it’s the part where you can grant access to your calendar for others). After doing so and re-running the script above, I now again get the 400 Error Invalid conference type value
.
The only thing that I can think of is that the putenv
call sets the value of the variable (checked with getenv
) to the absolute path to the .json
file holding the credentials, from the server’s root. Is that the intention? How are the credentials read/accessed? Just asking because the .json
file is in a 0500
directory and the .json
file itself also is 0500
, but this should be okay? And well, I’m stuck.
One thought I had: Does the Domain which you verify within your Google Workspace-Domain actually have to be the domain from which you send the API request / run the code above? Because that’s currently not the case…
2
Answers
As I've been struggling significantly with this and there are countless posts regarding issues with this setup / confusions about steps of the setup in this forum; here's a step-by-step guide, explaining how to properly setup the programmatic generation of Google Calendar Events for your desired Google Calendar, + generate related Google Meet Links.
What you will mainly need:
The steps are:
TXT
entry to your domain's DNS records and you're good to go).Create new User
andSetup Gmail
appear to be mandatory for the setup of new a Google Workspace Account, due to persistent popup telling you to do so, but it is actually not necessary at all. You should especially watch out in setting up your email via gmail, as this would ask you to remove all of yourMX
records from your DNS records, and insert one from Google. What this will do is activate the username of your Google Workspace mentioned in step 2. as a gmail account. BUT, as you have to remove allMX
records of your previous DNS settings for your business domain to do so, this will cause that all of your current business e-mails, registered by your host, will stop working. Which is why it is no problem to skip this part, if you already have an e-mail provider setup for your business domain.Google Calendar API
, click on it, and enable it.path/to/your/access_data.json
).Make changes and manage accesses
. Wait until its saved. If you don't do this, your API requests will result in a404 (Not found) error
.Calendar ID
, which will be needed in the code in the next step. This may be an e-mail address, yes, don't be confused.What I've struggled with is that, if you do not provide the username of your Google Workspace Account to the line:
Even if you provide for example the e-mail address of your GCP account, or your GCP service account, you will get a
400 (Bad Request)
Error back from the API, sayingInvalid conference type value
. This can be confusing, as it may be the case (which was the case for me) that a checkup of the concerence types which are allowed for your calendar, via this, still tells you that:Meaning that the creation of Google Meet Links is allowed for the concerned calendar. Hence the error you get from the API, saying
Invalid conference type value
is inaccurate; the actual problem is that you're not impersonating the Google Workspace Account User which you used to implement the domain-wide delegation to the service account you're using to send the request. Really struggled with this one.Anyways, after you do all of the above, it should all be working. And again, this implementation will not execute for free. Many websites tell you that the use of the Google Calendar API is free of charge, even chatGPT etc. But to do what's explained in my step-by-step guide, you need an active Google Workspace subscription; I've verified that with a quick support session with Google. Just so you know.
Happy scheduling!
Try this to your code to set the conff data as follows to generate a Google Calendar appointment with an automatic Google Meet link using the Google API client for PHP
Note:
/path/to/service_account_key.json
$calendarId
value.You have to install the Dipendency .. by
composer require google/apiclient