Open-Source Wikis

/

Cal.com

/

Apps

/

API v2

calcom/cal.com

API v2

Active contributors: Lauris, Carlos, Morgan, Eunjae

Purpose

apps/api/v2 is the official Cal.com Platform REST API — a separate NestJS service that lives next to the Next.js web app. It powers the documented public REST endpoints, the OAuth-client tenant model, and the React "atom" components in packages/platform/atoms that embed Cal.com scheduling into third-party products.

The API is documented at apps/docs/content/api-reference and exposes a Swagger UI when running locally.

Directory layout

apps/api/v2/
├── src/
│   ├── app.module.ts          # Root NestJS module
│   ├── app.controller.ts
│   ├── bootstrap.ts           # Bootstraps the Nest app (used by main.ts and tests)
│   ├── main.ts                # Production entry point
│   ├── env.ts                 # Typed env loading
│   ├── instrument.ts          # Sentry instrumentation
│   ├── config/                # NestJS config providers
│   ├── filters/               # Exception filters (HTTP, Prisma, validation)
│   ├── lib/                   # 16 lib subdirectories (api-keys, jwt, prisma, ...)
│   ├── middleware/            # Logger, redirects, rewrites, body parsers, request IDs
│   ├── modules/               # 32 NestJS modules (one per resource + cross-cutting)
│   ├── platform/              # Versioned platform endpoints (event-types_2024_06_14, bookings/2024-08-13, ...)
│   ├── swagger/               # Swagger doc generation
│   ├── vercel-webhook.controller.ts
│   ├── vercel-webhook.guard.ts
│   └── app.e2e-spec.ts
├── test/                      # Test fixtures + utilities
├── scripts/
├── jest.config.ts
├── jest-e2e.ts
├── nest-cli.json
├── Dockerfile
└── README.md / README-PLATFORM.md

Key abstractions

Symbol File Purpose
AppModule apps/api/v2/src/app.module.ts Root module; wires Sentry, Throttler (Redis-backed), Bull (jobs), Auth, JWT, Prisma, Endpoints
EndpointsModule apps/api/v2/src/modules/endpoints.module.ts Aggregates every resource module so the app boots from one import
CustomThrottlerGuard apps/api/v2/src/lib/throttler-guard.ts The actual rate-limiter used by the app (ThrottlerModule is configured to keep the guard active)
RequestIdMiddleware apps/api/v2/src/middleware/request-ids/request-id.middleware.ts Stamps every request with a request ID for log correlation
ResponseInterceptor apps/api/v2/src/middleware/request-ids/request-id.interceptor.ts Wraps responses in the standard envelope and propagates request IDs
RawBodyMiddleware / JsonBodyMiddleware / UrlencodedBodyMiddleware apps/api/v2/src/middleware/body/* Per-route body parsing — webhooks need raw bodies, OAuth token endpoint needs urlencoded
VercelWebhookController apps/api/v2/src/vercel-webhook.controller.ts Handles Vercel deployment webhooks
PrismaModule apps/api/v2/src/modules/prisma/prisma.module.ts Provides the shared Prisma client across the app
RedisModule apps/api/v2/src/modules/redis/redis.module.ts Connects to Redis for throttling, BullMQ, and short-lived caches
AuthModule / JwtModule apps/api/v2/src/modules/{auth,jwt} API-key, OAuth, and JWT authentication strategies

How it works

graph TD
    Client -->|HTTPS| Nest[apps/api/v2 NestJS]
    Nest --> Middleware[middleware/*]
    Middleware --> Throttler[CustomThrottlerGuard via Redis]
    Throttler --> AuthGuards[Auth + JWT guards]
    AuthGuards --> Controllers[modules/*/controllers]
    Controllers --> Services[modules/*/services]
    Services --> PlatformLibs[packages/platform/libraries]
    PlatformLibs --> Features[packages/features/*]
    Services --> Prisma[(PostgreSQL)]
    Services --> Redis[(Redis)]
    Services --> Bull[BullMQ jobs]
    Nest --> Sentry[Sentry]

The crucial detail is the packages/platform/libraries/index.ts indirection. apps/api/v2's tsconfig.json does not have path mappings for @calcom/features or @calcom/trpc, so those modules are re-exported through @calcom/platform-libraries. AGENTS.md documents this rule with examples.

Modules (resources)

The 32 directories under apps/api/v2/src/modules/ map to public resources, one per concept:

api-keys, apps, atoms, auth, booking-seat, cal-unified-calendars,
conferencing, credentials, deployments, destination-calendars,
email, event-types, jwt, kysely, memberships, oauth-clients, ooo,
organizations, prisma, profiles, redis, selected-calendars, slots,
stripe, teams, timezones, tokens, users, verified-resources,
webhooks

Versioned endpoints live under apps/api/v2/src/platform/. Each version is its own folder (e.g., event-types_2024_06_14/, bookings/2024-08-13/) so the team can ship breaking changes by introducing a new version while keeping the old one available.

Almost every controller has an *.e2e-spec.ts neighbor. The repo has 42 such e2e spec files, run by .github/workflows/e2e-api-v2.yml.

Authentication

apps/api/v2/src/modules/auth/ implements three flows:

  • API key — long-lived bearer tokens. The Cal-Api-Key legacy packages/features/api-keys-legacy package handles compatibility.
  • OAuth 2.0 (clients) — for Platform tenants. The oauth-clients module owns client registration and token issuance; the tokens module manages access/refresh tokens.
  • JWT — for short-lived service-to-service auth.

The RawBodyMiddleware is explicitly applied to /v2/auth/oauth2/token because OAuth requires application/x-www-form-urlencoded parsing, and to billing webhooks which need raw bodies for signature verification.

Rate limiting

CustomThrottlerGuard is registered as APP_GUARD so it runs on every request. The ThrottlerModule configuration in app.module.ts keeps the upstream @nestjs/throttler machinery live (with a dummy throttler) but the actual rules are read by CustomThrottlerGuard via Redis.

Background jobs

Bull/BullMQ runs through BullModule.forRoot in app.module.ts, connected to REDIS_URL. Per-resource queues live inside individual modules.

Integration points

  • Web app — There is no direct call between web and API v2 in production. They share the same database via PrismaModule. The web app uses tRPC; the API v2 is a standalone REST service.
  • Platform atomspackages/platform/atoms (React) calls API v2 endpoints over HTTPS using a typed SDK in packages/platform/types and packages/platform/libraries.
  • Documentation — Swagger decorators in controllers feed apps/api/v2/src/swagger/ which generates apps/docs/content/api-reference/v2/openapi.json.
  • Sentryapps/api/v2/src/instrument.ts initializes Sentry; SentryGlobalFilter is registered as APP_FILTER.

Entry points for modification

  • Add a new resource: scaffold a NestJS module under apps/api/v2/src/modules/<resource>/ (controller, service, module). Register it in apps/api/v2/src/modules/endpoints.module.ts. Add Swagger decorators on the controller methods so the OpenAPI spec picks them up. Re-export shared logic via packages/platform/libraries/index.ts if you need symbols from @calcom/features.
  • Add a new endpoint version: create apps/api/v2/src/platform/<resource>/<YYYY-MM-DD>/ with controllers and DTOs scoped to the new version. Update the version routing in the resource module.
  • Auth changes: anything that touches sessions, scopes, or guards belongs in apps/api/v2/src/modules/auth/ plus apps/api/v2/src/modules/jwt/.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

API v2 – Cal.com wiki | Factory