SapanCalDeveloper Docs

Connecting calendars

Send users through the hosted connect page, handle every outcome, and relink connections that stop working.

Users connect their Google or Microsoft calendar on a page BentoCal hosts. You don't write any OAuth code: your server creates a connect session, sends the user to its URL, and checks the result when they come back.

The flow

  1. Your server calls POST /connect_sessions with your id for the user and a registered redirect_uri.
  2. You send the user to the returned url (a redirect, a link or a popup).
  3. On the hosted page they accept the terms, choose Google or Microsoft and sign in.
  4. BentoCal sends them back to your redirect_uri with the result in the query string.
  5. Your server confirms the result with GET /connect_sessions/{id} or the connection.created webhook.
Bash
curl -X POST https://api.bentocal.com/au/v1/connect_sessions \
  -H "Authorization: Bearer $BENTOCAL_TEST_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "user_id": "user_123",
    "redirect_uri": "https://app.example.com/calendar/connected"
  }'

The response has the session id, the url to send the user to and expires_at. Each session can be used once and expires after 30 minutes. Create a new one each time the user clicks "Connect calendar".

What the user sees

The hosted connect page: the app's logo, "Connect your calendar", what the app can access, a terms checkbox and buttons for Google and Microsoft

The page shows your application's name and logo, what it will be able to do (see free/busy time, add and update events), and a checkbox to accept BentoCal's terms. The page follows the user's light or dark mode.

Set the name and logo on the application's Settings tab under Branding: Display name is your product name as your users know it, and Logo is an image under 1 MB. Without a logo, the page shows the first letter of the display name.

Redirect URIs

redirect_uri must exactly match one of the URIs on the application's Settings tab, under Redirect URIs. Otherwise the request fails with 400 invalid_request.

  • https only. Development applications may also use http://localhost and http://127.0.0.1.
  • No #fragment, at most 2048 characters, up to 20 per application.

Handle the redirect

When the flow ends, the user is redirected (303) to:

Plain Text
{redirect_uri}?connect_session_id=cs_…&status=success
statusMeaning
successA calendar was connected or relinked.
deniedThe user declined at Google or Microsoft.
errorSomething went wrong. error_code says what.
error_codeMeaning
account_mismatchDuring a relink the user signed in to a different account from the one being relinked.
connection_limit_reachedThe company reached the development limit. See Development and production.
connection_not_foundThe connection being relinked was deleted while the user was signing in.
session_expiredThe user took longer than 30 minutes.
internal_errorAn unexpected error. Try again.

New codes may be added, so treat unknown ones like internal_error.

Anyone can edit a query string. Use it to decide what to show the user, then confirm the result from your server with GET /connect_sessions/{connect_session_id} (or the connection.created webhook) before you rely on it.

Session statuses

GET /connect_sessions/{connect_session_id} returns the session with one of these statuses:

statusMeaning
pendingCreated, not opened yet.
redirectedThe user went on to Google or Microsoft.
completedA connection was made or relinked. connection holds it.
deniedThe user declined at the provider.
errorSee error_code.
expiredNot finished within 30 minutes.

After connecting

  • The user exists from now on: use your user id with free/busy and availability and events.
  • If the user had no usable connection, the new one becomes their default connection, which events are written to.
  • A connection.created webhook is sent. BentoCal also starts watching the account's primary calendar, so you get calendar.changed webhooks if you subscribe to them.
  • A user can connect several accounts by going through the flow again. Connecting an account they already connected updates that same connection and sends connection.relinked.

Choose the provider

Pass provider (google or microsoft) to offer only that provider on the connect page. The page still shows, with its terms checkbox, but only one button.

JSON
{ "user_id": "user_123", "redirect_uri": "https://app.example.com/calendar/connected", "provider": "microsoft" }

Google and Microsoft can stop accepting a connection's access, for example when the user changes their password or removes your app's access. BentoCal then marks the connection relink_required, sends a connection.relink_required webhook, and calls that need the connection fail with 409 relink_required.

To fix it, send the user through a connect session for that connection:

JSON
{ "user_id": "user_123", "redirect_uri": "https://app.example.com/calendar/connected", "connection_id": "conn_4kT9pQ2vXa7LmN3s" }

The page says Reconnect your calendar and asks the user to sign in again as the same account. If they do, the connection keeps its id and goes back to active, and connection.relinked is sent. If they sign in to a different account, the session ends with error_code: account_mismatch.

Some organisations stop their users from approving third-party apps themselves. Those users see "Need admin approval" from Microsoft instead of the consent screen.

The application's Admin consent tab has an Admin consent link to send to that organisation's IT team. Once a Microsoft 365 global admin approves your application, everyone in their tenant can connect. The connect page also shows users a "Work or school Microsoft account that needs approval? Ask your IT admin." link to the same page.

Google Workspace has no equivalent link. Workspace admins can allow BentoCal in their Admin console under Security, API controls, App access control.