SDK examples
Point official Google Calendar clients in TypeScript, Python, Go, Java, and C# at Calendarpit.
Point your app's official Google Calendar SDK client at Calendarpit. You do not need a Calendarpit-specific SDK.
The examples below list calendars and query FreeBusy.
Before you call the SDK
Prepare an access token and the SDK packages first:
- Start Calendarpit, for example with
calendarpit serve. See Run and configure. - Complete the local OAuth flow with the
https://www.googleapis.com/auth/calendarscope. If you need a refresh token, addaccess_type=offline. - Set
CALENDARPIT_ACCESS_TOKENin your shell to the resulting access token. The token is valid for one hour. - Install the packages listed in each tab in your project. Calendarpit does not install language runtimes or SDK packages for you.
The examples read CALENDARPIT_ACCESS_TOKEN directly. It is not a Google SDK setting.
These snippets pass an existing access token. They show how to route Calendar API requests to Calendarpit.
- They do not handle authorization callbacks or automatic token refresh.
- To refresh tokens, call
POST /oauth/token. Then update the client's token or recreate the client.
See Connect your app for the sample app and full OAuth client configuration.
Configure the service URL
Each library expects a different endpoint format.
- Preserve trailing slashes where shown.
- If Calendarpit runs on another host or port, replace
127.0.0.1:4173in every value.
| Language | SDK setting | Value |
|---|---|---|
| TypeScript / JavaScript | rootUrl | http://127.0.0.1:4173/ |
| Python | client_options.api_endpoint | http://127.0.0.1:4173/calendar/v3/ |
| Go | option.WithEndpoint | http://127.0.0.1:4173/calendar/v3/ |
| Java | setRootUrl + setServicePath | http://127.0.0.1:4173/ + calendar/v3/ |
| C# / .NET | BaseClientService.Initializer.BaseUri | http://127.0.0.1:4173/calendar/v3/ |
Every FreeBusy example sends POST /calendar/v3/freeBusy to Calendarpit. Event CRUD and calendar-list calls on the same client also use that local URL.
For calendarList, these methods are supported: list, get, insert, patch, update, delete, and watch. The single-owner limits in Calendar API compatibility apply.
Only the operations listed in Calendar API compatibility are supported, even if the SDK exposes more methods.
List calendars and query FreeBusy
- Packages:
@googleapis/calendarandgoogle-auth-library. - Runtime: Bun, or Node.js 22 or later as an ES module (
.mjs). - Monolithic package:
googleapisalso acceptsgoogle.calendar({ version: 'v3', auth, rootUrl }).
import { calendar } from '@googleapis/calendar';
import { OAuth2Client } from 'google-auth-library';
const token = process.env.CALENDARPIT_ACCESS_TOKEN;
if (!token) throw new Error('Set CALENDARPIT_ACCESS_TOKEN first.');
const auth = new OAuth2Client();
auth.setCredentials({ access_token: token });
const api = calendar({
version: 'v3',
auth,
rootUrl: 'http://127.0.0.1:4173/',
});
const calendars = await api.calendarList.list();
console.log(calendars.data.items);
const { data } = await api.freebusy.query({
requestBody: {
timeMin: '2026-10-19T00:00:00+09:00',
timeMax: '2026-10-20T00:00:00+09:00',
timeZone: 'Asia/Tokyo',
items: [{ id: 'primary' }],
},
});
console.log(data.calendars?.primary?.busy ?? []);This access-token-only client cannot refresh tokens. For full OAuth setup, use the local endpoints configuration shown in Connect your app.
Reference: Google Calendar Node.js client implementation.
- Packages:
google-api-python-client(2.x) andgoogle-auth. - Discovery:
static_discovery=Trueuses the discovery document bundled with the installed library. Building the client therefore does not fetch discovery metadata from Google. - Endpoint:
api_endpointincludes the/calendar/v3/path.
import os
from google.oauth2.credentials import Credentials
from googleapiclient.discovery import build
credentials = Credentials(token=os.environ["CALENDARPIT_ACCESS_TOKEN"])
with build(
"calendar",
"v3",
credentials=credentials,
static_discovery=True,
cache_discovery=False,
client_options={
"api_endpoint": "http://127.0.0.1:4173/calendar/v3/",
},
) as api:
print(api.calendarList().list().execute().get("items", []))
result = api.freebusy().query(body={
"timeMin": "2026-10-19T00:00:00+09:00",
"timeMax": "2026-10-20T00:00:00+09:00",
"timeZone": "Asia/Tokyo",
"items": [{"id": "primary"}],
}).execute()
print(result["calendars"]["primary"]["busy"])If you pass a refresh token to Credentials:
- Also supply the registered client ID, client secret, and
token_uri="http://127.0.0.1:4173/oauth/token". - Omit
scopes, or pass the exact granted scopes in the same order.
Configure the authorization, userinfo, and revocation URLs separately in your app's OAuth flow.
References: bundled discovery documents, endpoint selection.
- Modules:
google.golang.org/apiandgolang.org/x/oauth2. - Credentials: Supply an explicit token source. This keeps the client from looking up Google Application Default Credentials.
package main
import (
"context"
"fmt"
"log"
"os"
"golang.org/x/oauth2"
"google.golang.org/api/calendar/v3"
"google.golang.org/api/option"
)
func main() {
token := os.Getenv("CALENDARPIT_ACCESS_TOKEN")
if token == "" {
log.Fatal("Set CALENDARPIT_ACCESS_TOKEN first.")
}
api, err := calendar.NewService(context.Background(),
option.WithEndpoint("http://127.0.0.1:4173/calendar/v3/"),
option.WithTokenSource(oauth2.StaticTokenSource(&oauth2.Token{
AccessToken: token,
TokenType: "Bearer",
})),
)
if err != nil {
log.Fatal(err)
}
calendars, err := api.CalendarList.List().Do()
if err != nil {
log.Fatal(err)
}
for _, c := range calendars.Items {
fmt.Println(c.Id)
}
result, err := api.Freebusy.Query(&calendar.FreeBusyRequest{
TimeMin: "2026-10-19T00:00:00+09:00",
TimeMax: "2026-10-20T00:00:00+09:00",
TimeZone: "Asia/Tokyo",
Items: []*calendar.FreeBusyRequestItem{{Id: "primary"}},
}).Do()
if err != nil {
log.Fatal(err)
}
for _, b := range result.Calendars["primary"].Busy {
fmt.Println(b.Start, "-", b.End)
}
}StaticTokenSource never refreshes tokens. For SDK-managed OAuth:
- Set
oauth2.Config.Endpoint.AuthURLandTokenURLto Calendarpit's OAuth endpoints. - Pass
config.TokenSource(ctx, token).
References: Calendar client, WithEndpoint, OAuth configuration.
- Artifacts:
com.google.apis:google-api-services-calendar,com.google.http-client:google-http-client, andcom.google.http-client:google-http-client-gson. - Java version: This example uses Java 11 or later.
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.gson.GsonFactory;
import com.google.api.client.util.DateTime;
import com.google.api.services.calendar.Calendar;
import com.google.api.services.calendar.model.FreeBusyRequest;
import com.google.api.services.calendar.model.FreeBusyRequestItem;
import java.util.List;
public class CalendarpitExample {
public static void main(String[] args) throws Exception {
String token = System.getenv("CALENDARPIT_ACCESS_TOKEN");
if (token == null || token.isBlank()) {
throw new IllegalStateException("Set CALENDARPIT_ACCESS_TOKEN first.");
}
Calendar api = new Calendar.Builder(
new NetHttpTransport(),
GsonFactory.getDefaultInstance(),
request -> request.getHeaders().setAuthorization("Bearer " + token)
)
.setRootUrl("http://127.0.0.1:4173/")
.setServicePath("calendar/v3/")
.setApplicationName("Calendarpit local example")
.build();
System.out.println(api.calendarList().list().execute().getItems());
FreeBusyRequest body = new FreeBusyRequest()
.setTimeMin(new DateTime("2026-10-19T00:00:00+09:00"))
.setTimeMax(new DateTime("2026-10-20T00:00:00+09:00"))
.setTimeZone("Asia/Tokyo")
.setItems(List.of(new FreeBusyRequestItem().setId("primary")));
var result = api.freebusy().query(body).execute();
System.out.println(result.getCalendars().get("primary").getBusy());
}
}The request initializer sets the bearer token header directly. Obtain and refresh tokens using the local OAuth endpoints.
Setting setRootUrl does not redirect separate Google authorization helpers.
References: Calendar builder, FreeBusy request.
- NuGet packages:
Google.Apis.Calendar.v3andGoogle.Apis.Auth. - Project type: A console application with top-level statements.
using System;
using System.Collections.Generic;
using Google.Apis.Auth.OAuth2;
using Google.Apis.Calendar.v3;
using Google.Apis.Calendar.v3.Data;
using Google.Apis.Services;
var token = Environment.GetEnvironmentVariable("CALENDARPIT_ACCESS_TOKEN");
if (string.IsNullOrWhiteSpace(token))
throw new InvalidOperationException("Set CALENDARPIT_ACCESS_TOKEN first.");
using var api = new CalendarService(new BaseClientService.Initializer
{
BaseUri = "http://127.0.0.1:4173/calendar/v3/",
HttpClientInitializer = GoogleCredential.FromAccessToken(token),
ApplicationName = "Calendarpit local example",
});
var calendars = await api.CalendarList.List().ExecuteAsync();
foreach (var calendar in calendars.Items)
Console.WriteLine(calendar.Id);
var result = await api.Freebusy.Query(new FreeBusyRequest
{
TimeMinRaw = "2026-10-19T00:00:00+09:00",
TimeMaxRaw = "2026-10-20T00:00:00+09:00",
TimeZone = "Asia/Tokyo",
Items = new List<FreeBusyRequestItem>
{
new FreeBusyRequestItem { Id = "primary" },
},
}).ExecuteAsync();
foreach (var interval in result.Calendars["primary"].Busy)
Console.WriteLine($"{interval.StartRaw} - {interval.EndRaw}");FromAccessToken does not refresh tokens. Refresh via the local token endpoint, then recreate the credentials.
BaseUri configures Calendar API requests only. It does not redirect OAuth helpers.
References: service base URI, access-token credentials, FreeBusy request.
You can call the same HTTP endpoints directly from any language.
curl --fail-with-body http://127.0.0.1:4173/calendar/v3/users/me/calendarList \
-H "Authorization: Bearer $CALENDARPIT_ACCESS_TOKEN"
curl --fail-with-body http://127.0.0.1:4173/calendar/v3/freeBusy \
-H "Authorization: Bearer $CALENDARPIT_ACCESS_TOKEN" \
-H 'Content-Type: application/json' \
--data '{
"timeMin": "2026-10-19T00:00:00+09:00",
"timeMax": "2026-10-20T00:00:00+09:00",
"timeZone": "Asia/Tokyo",
"items": [{"id": "primary"}]
}'Expected result
primary resolves to the primary calendar of the authenticated test user.
For Alex in the default fixture, this query returns one busy interval: 10:00 to 11:00 on October 19, 2026, in Asia/Tokyo.
Editing events in the admin UI changes the next FreeBusy response. Transparent and cancelled events do not count as busy time.
Verification status
Only the Bun/TypeScript sample app in Connect your app has an automated end-to-end test.
The examples on this page, including the TypeScript example, follow the official client APIs. They have not been compiled or run in this repository's CI.
For common configuration and request errors, see Troubleshooting.