curl --request POST \
--url https://app.base44.com/api/apps/{app_id}/external-auth/initiate \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"integration_type": "googlecalendar",
"scopes": [
"https://www.googleapis.com/auth/calendar.readonly"
],
"force_reconnect": false,
"connection_config": {
"subdomain": "acme-prod"
},
"connector_id": "6820f3a4e7b91d003c45a1f9",
"notify_chat_on_success": false
}
'import requests
url = "https://app.base44.com/api/apps/{app_id}/external-auth/initiate"
payload = {
"integration_type": "googlecalendar",
"scopes": ["https://www.googleapis.com/auth/calendar.readonly"],
"force_reconnect": False,
"connection_config": { "subdomain": "acme-prod" },
"connector_id": "6820f3a4e7b91d003c45a1f9",
"notify_chat_on_success": False
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
integration_type: 'googlecalendar',
scopes: ['https://www.googleapis.com/auth/calendar.readonly'],
force_reconnect: false,
connection_config: {subdomain: 'acme-prod'},
connector_id: '6820f3a4e7b91d003c45a1f9',
notify_chat_on_success: false
})
};
fetch('https://app.base44.com/api/apps/{app_id}/external-auth/initiate', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://app.base44.com/api/apps/{app_id}/external-auth/initiate",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'integration_type' => 'googlecalendar',
'scopes' => [
'https://www.googleapis.com/auth/calendar.readonly'
],
'force_reconnect' => false,
'connection_config' => [
'subdomain' => 'acme-prod'
],
'connector_id' => '6820f3a4e7b91d003c45a1f9',
'notify_chat_on_success' => false
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://app.base44.com/api/apps/{app_id}/external-auth/initiate"
payload := strings.NewReader("{\n \"integration_type\": \"googlecalendar\",\n \"scopes\": [\n \"https://www.googleapis.com/auth/calendar.readonly\"\n ],\n \"force_reconnect\": false,\n \"connection_config\": {\n \"subdomain\": \"acme-prod\"\n },\n \"connector_id\": \"6820f3a4e7b91d003c45a1f9\",\n \"notify_chat_on_success\": false\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://app.base44.com/api/apps/{app_id}/external-auth/initiate")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"integration_type\": \"googlecalendar\",\n \"scopes\": [\n \"https://www.googleapis.com/auth/calendar.readonly\"\n ],\n \"force_reconnect\": false,\n \"connection_config\": {\n \"subdomain\": \"acme-prod\"\n },\n \"connector_id\": \"6820f3a4e7b91d003c45a1f9\",\n \"notify_chat_on_success\": false\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.base44.com/api/apps/{app_id}/external-auth/initiate")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"integration_type\": \"googlecalendar\",\n \"scopes\": [\n \"https://www.googleapis.com/auth/calendar.readonly\"\n ],\n \"force_reconnect\": false,\n \"connection_config\": {\n \"subdomain\": \"acme-prod\"\n },\n \"connector_id\": \"6820f3a4e7b91d003c45a1f9\",\n \"notify_chat_on_success\": false\n}"
response = http.request(request)
puts response.read_body{
"redirect_url": "https://app.base44.com/api/external-auth/connect/3f9c2a7e5b8d4c1fa6e0d2b7c9a1e4f3",
"connection_id": "base44_6820f3a4e7b91d003c45a1f7",
"integration_type": "googlecalendar",
"already_authorized": false,
"error": "different_user",
"error_message": "Integration googlecalendar is already authorized by a different user for this app."
}Start connector connection
Starts connecting a third-party account to the app with OAuth, and returns a link where a person signs in to the provider and approves access. The connection is recorded as yours, whichever provider account approves it.
Connecting is done in steps:
- Call this endpoint and open
redirect_urlin a browser. - Sign in to the provider and approve the requested scopes. This has to happen within five minutes of the call, and the link itself stops working after 10 minutes.
- Poll Get connector connection status with the returned
connection_iduntil it’sACTIVEorFAILED.
redirect_url as a credential. Whoever approves access through it connects their provider account to the app.A successful call doesn’t always start an authorization. Read already_authorized and error first. When the app already has a working connection that covers the scopes, there’s nothing to open. When another collaborator’s account is connected, the call reports different_user. With integration_type, send force_reconnect to replace it with yours.
Retrying starts a new authorization with a new link rather than returning the earlier one, so open the link from the latest response.
Send integration_type to connect through Base44’s OAuth app, or connector_id for a workspace connector that uses the workspace’s own OAuth app. The call is refused when the workspace has turned off builder connections for the connector, and connectors with an auth_method of platform_credentials can’t be connected this way.
This is limited to 15 requests a minute per caller. Some workspaces have a different limit.
curl --request POST \
--url https://app.base44.com/api/apps/{app_id}/external-auth/initiate \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"integration_type": "googlecalendar",
"scopes": [
"https://www.googleapis.com/auth/calendar.readonly"
],
"force_reconnect": false,
"connection_config": {
"subdomain": "acme-prod"
},
"connector_id": "6820f3a4e7b91d003c45a1f9",
"notify_chat_on_success": false
}
'import requests
url = "https://app.base44.com/api/apps/{app_id}/external-auth/initiate"
payload = {
"integration_type": "googlecalendar",
"scopes": ["https://www.googleapis.com/auth/calendar.readonly"],
"force_reconnect": False,
"connection_config": { "subdomain": "acme-prod" },
"connector_id": "6820f3a4e7b91d003c45a1f9",
"notify_chat_on_success": False
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
integration_type: 'googlecalendar',
scopes: ['https://www.googleapis.com/auth/calendar.readonly'],
force_reconnect: false,
connection_config: {subdomain: 'acme-prod'},
connector_id: '6820f3a4e7b91d003c45a1f9',
notify_chat_on_success: false
})
};
fetch('https://app.base44.com/api/apps/{app_id}/external-auth/initiate', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://app.base44.com/api/apps/{app_id}/external-auth/initiate",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'integration_type' => 'googlecalendar',
'scopes' => [
'https://www.googleapis.com/auth/calendar.readonly'
],
'force_reconnect' => false,
'connection_config' => [
'subdomain' => 'acme-prod'
],
'connector_id' => '6820f3a4e7b91d003c45a1f9',
'notify_chat_on_success' => false
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://app.base44.com/api/apps/{app_id}/external-auth/initiate"
payload := strings.NewReader("{\n \"integration_type\": \"googlecalendar\",\n \"scopes\": [\n \"https://www.googleapis.com/auth/calendar.readonly\"\n ],\n \"force_reconnect\": false,\n \"connection_config\": {\n \"subdomain\": \"acme-prod\"\n },\n \"connector_id\": \"6820f3a4e7b91d003c45a1f9\",\n \"notify_chat_on_success\": false\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://app.base44.com/api/apps/{app_id}/external-auth/initiate")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"integration_type\": \"googlecalendar\",\n \"scopes\": [\n \"https://www.googleapis.com/auth/calendar.readonly\"\n ],\n \"force_reconnect\": false,\n \"connection_config\": {\n \"subdomain\": \"acme-prod\"\n },\n \"connector_id\": \"6820f3a4e7b91d003c45a1f9\",\n \"notify_chat_on_success\": false\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.base44.com/api/apps/{app_id}/external-auth/initiate")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"integration_type\": \"googlecalendar\",\n \"scopes\": [\n \"https://www.googleapis.com/auth/calendar.readonly\"\n ],\n \"force_reconnect\": false,\n \"connection_config\": {\n \"subdomain\": \"acme-prod\"\n },\n \"connector_id\": \"6820f3a4e7b91d003c45a1f9\",\n \"notify_chat_on_success\": false\n}"
response = http.request(request)
puts response.read_body{
"redirect_url": "https://app.base44.com/api/external-auth/connect/3f9c2a7e5b8d4c1fa6e0d2b7c9a1e4f3",
"connection_id": "base44_6820f3a4e7b91d003c45a1f7",
"integration_type": "googlecalendar",
"already_authorized": false,
"error": "different_user",
"error_message": "Integration googlecalendar is already authorized by a different user for this app."
}Authorizations
Personal access token, sent as Authorization: Bearer <token>.
Path Parameters
ID of the app.
Body
Connector to connect through Base44's OAuth app, from integration_type in List connectors. Send this or connector_id, not both.
googlecalendar, google_classroom, googledrive, gmail, googlesheets, googledocs, googleslides, googlebigquery, googlemeet, googletasks, googleads, google_analytics, google_search_console, slack, notion, salesforce, hubspot, linkedin, tiktok, instagram, discord, slackbot, wix, github, gitlab, bamboohr, dropbox, clickup, wrike, box, outlook, linear, airtable, microsoft_teams, share_point, one_drive, typeform, splitwise, hugging_face, calendly, contentful, supabase, snowflake, databricks, quickbooks, square "googlecalendar"
OAuth scopes to ask the provider for. Scopes the app's current connection already has are kept unless force_reconnect is true. Defaults to an empty list, which asks for the connector's default scopes.
[
"https://www.googleapis.com/auth/calendar.readonly"
]
Whether to start a new authorization even when the app already has a working connection that covers the scopes. Send true to switch to another account. Applies only with integration_type. Defaults to false.
false
Values the connector needs before authorization, keyed by the name of each field from Get connector connection fields. Leave it out for connectors that have no fields.
Show child attributes
Show child attributes
{ "subdomain": "acme-prod" }
ID of a workspace connector that uses the workspace's own OAuth app, set up in the workspace settings. Send this or integration_type, not both.
"6820f3a4e7b91d003c45a1f9"
Whether a successful connection adds a message to the app's AI chat so the AI picks up wiring the connector into the app. Applies only with integration_type. Defaults to false.
false
Response
The authorization was started, or the response says why none was needed.
The start of a connector authorization, or why none was needed.
Link to open in a browser so the user can sign in to the provider and approve access. It expires after 10 minutes. Treat it as a credential. The value is null when no authorization was started.
"https://app.base44.com/api/external-auth/connect/3f9c2a7e5b8d4c1fa6e0d2b7c9a1e4f3"
ID of the connection being authorized. Pass it to Get connector connection status. When already_authorized is true it's the existing connection, or null if you sent connector_id. The value is null when error is set.
"base44_6820f3a4e7b91d003c45a1f7"
Connector being connected. Without connector_id, the value is null when already_authorized is true or error is set.
googlecalendar, google_classroom, googledrive, gmail, googlesheets, googledocs, googleslides, googlebigquery, googlemeet, googletasks, googleads, google_analytics, google_search_console, slack, notion, salesforce, hubspot, linkedin, tiktok, instagram, discord, slackbot, wix, github, gitlab, bamboohr, dropbox, clickup, wrike, box, outlook, linear, airtable, microsoft_teams, share_point, one_drive, typeform, splitwise, hugging_face, calendly, contentful, supabase, snowflake, databricks, quickbooks, square "googlecalendar"
Whether the app already has a working connection that covers the requested scopes (true), so there's nothing to open, or not (false).
false
Why no authorization was started, or null if one was. Either different_user, when another collaborator's account is already connected (with integration_type, send force_reconnect to replace it), or service_unavailable, when the provider can't be reached. Retry later.
"different_user"
Readable explanation of error, or null when error is null.
"Integration googlecalendar is already authorized by a different user for this app."
Was this page helpful?