Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/DavidCevallos15/inforario-IA-null/llms.txt

Use this file to discover all available pages before exploring further.

The google-calendar-sync function is a Deno Edge Function deployed on Supabase. It reads a signed-in user’s Google OAuth2 tokens from the user_calendar_tokens database table, automatically refreshes the access token if it is about to expire, and then creates the supplied events in the user’s Google Calendar. All token management — including persisting refreshed tokens back to the database — happens inside the function; the calling client never handles OAuth credentials directly. The function is implemented using serve from deno.land/std@0.224.0/http/server.ts, not the newer Deno.serve global.
Users must connect their Google Calendar account before calling this endpoint. The function looks up stored tokens by the authenticated user’s ID. If no row exists in user_calendar_tokens for that user, the function returns 400. Direct the user to complete the Google OAuth2 flow and ensure a row is inserted before invoking this endpoint.

Endpoint

POST https://{project}.supabase.co/functions/v1/google-calendar-sync
The function accepts POST requests only. OPTIONS preflight requests are answered immediately with the shared CORS headers and a 200 ok body.

CORS headers

All responses (including OPTIONS preflight) include the following headers defined in _shared/cors.ts:
HeaderValue
Access-Control-Allow-Origin*
Access-Control-Allow-Headersauthorization, x-client-info, apikey, content-type
Access-Control-Allow-MethodsPOST, GET, OPTIONS, PUT, DELETE

Authentication

This endpoint requires a Supabase user JWT — not the anon key. The token must belong to an authenticated user whose session was obtained via supabase.auth.signIn*. The function calls supabase.auth.getUser() to verify the token server-side and resolve the caller’s user_id.
Authorization: Bearer <supabase-user-jwt>
Passing the anon key in the Authorization header will cause supabase.auth.getUser() to return no user, and the function will respond with 401 Usuario no autenticado.

Request

Headers

HeaderRequiredValue
AuthorizationBearer <supabase-user-jwt>
Content-Typeapplication/json

Body

events
CalendarEventInput[]
required
Array of one or more event objects to create in Google Calendar. Must contain at least one entry — an empty array returns 400.
calendarId
string
Google Calendar ID to add the events to. Defaults to "primary" (the user’s default calendar) when not provided.

TypeScript type

type CalendarEventInput = {
  summary: string;
  description?: string;
  location?: string;
  start: {
    dateTime: string;
    timeZone: string;
  };
  end: {
    dateTime: string;
    timeZone: string;
  };
  recurrence?: string[];
};

Example request

curl -X POST \
  https://{project}.supabase.co/functions/v1/google-calendar-sync \
  -H "Authorization: Bearer <supabase-user-jwt>" \
  -H "Content-Type: application/json" \
  -d '{
    "calendarId": "primary",
    "events": [
      {
        "summary": "SISTEMAS DISTRIBUIDOS",
        "description": "Docente: PÉREZ JUAN | Aula 301, Piso 3",
        "location": "Aula 301, Piso 3",
        "start": {
          "dateTime": "2025-02-03T07:00:00",
          "timeZone": "America/Guayaquil"
        },
        "end": {
          "dateTime": "2025-02-03T09:00:00",
          "timeZone": "America/Guayaquil"
        },
        "recurrence": ["RRULE:FREQ=WEEKLY;UNTIL=20250730T235959Z"]
      },
      {
        "summary": "BASES DE DATOS AVANZADAS",
        "description": "Docente: GÓMEZ ANA | Aula 205, Piso 2",
        "location": "Aula 205, Piso 2",
        "start": {
          "dateTime": "2025-02-05T09:00:00",
          "timeZone": "America/Guayaquil"
        },
        "end": {
          "dateTime": "2025-02-05T11:00:00",
          "timeZone": "America/Guayaquil"
        },
        "recurrence": ["RRULE:FREQ=WEEKLY;UNTIL=20250730T235959Z"]
      }
    ]
  }'

Response

200 — Success

success
boolean
Always true on a 200 response.
message
string
Human-readable summary, e.g. "Se crearon 2 evento(s) en Google Calendar.".
events
array
Array of objects describing each event that was successfully created in Google Calendar.

Example success response

{
  "success": true,
  "message": "Se crearon 2 evento(s) en Google Calendar.",
  "events": [
    {
      "id": "abc123xyz_20250203T070000Z",
      "htmlLink": "https://www.google.com/calendar/event?eid=abc123xyz"
    },
    {
      "id": "def456uvw_20250205T090000Z",
      "htmlLink": "https://www.google.com/calendar/event?eid=def456uvw"
    }
  ]
}

Error responses

All error responses include a success: false field alongside the message field.
StatusConditionmessage value
400events array is missing or empty"Debes enviar al menos un evento."
400No token row found in user_calendar_tokens for the user"No hay tokens de Google Calendar para este usuario. Conecta Google primero."
400Access token is expired but refresh_token is null"Tu cuenta no tiene refresh token. Reconecta Google Calendar para continuar."
401Authorization header is absent"Falta el token de autenticación."
401JWT is present but resolves to no user"Usuario no autenticado."
405Request method is not POST"Método no permitido."
500SUPABASE_URL or SUPABASE_ANON_KEY not set"Faltan variables SUPABASE_URL o SUPABASE_ANON_KEY."
500GOOGLE_CLIENT_ID or GOOGLE_CLIENT_SECRET not set"Faltan secretos GOOGLE_CLIENT_ID o GOOGLE_CLIENT_SECRET."
500Token DB update failed after a mid-flight refresh"No se pudo guardar el token refrescado después de un 401."
500Unexpected runtime error"<error message>"
502+Google Calendar API returned a non-OK statusForwarded Google error message

Environment variables

SUPABASE_URL
string
required
The base URL of your Supabase project (e.g., https://xxxx.supabase.co). Used to initialise the Supabase client that verifies the user JWT and reads/writes token rows.
SUPABASE_ANON_KEY
string
required
The public anon key of your Supabase project. Combined with the user-supplied JWT via the Authorization header to create an RLS-aware Supabase client.
GOOGLE_CLIENT_ID
string
required
OAuth2 client ID from Google Cloud Console. Required to refresh expired access tokens.
GOOGLE_CLIENT_SECRET
string
required
OAuth2 client secret from Google Cloud Console. Required to refresh expired access tokens.

Token refresh logic

The function checks whether the stored access token needs refreshing before it attempts to create any calendar events. The check uses a 60-second safety margin (REFRESH_MARGIN_MS = 60 * 1000 ms): if the stored expiry_date is within 60 seconds of the current time — or is null, missing, or unparseable — the token is considered expired and is refreshed proactively. The token refresh endpoint used is https://oauth2.googleapis.com/token and the Google Calendar API base URL is https://www.googleapis.com/calendar/v3. Pre-flight refresh flow:
1. Read token row from user_calendar_tokens for authenticated user.
2. If expiry_date ≤ now + 60 000 ms (REFRESH_MARGIN_MS):
     POST https://oauth2.googleapis.com/token
       grant_type=refresh_token
       client_id, client_secret, refresh_token
     → Receive new access_token, expires_in, (optionally) new refresh_token.
     UPDATE user_calendar_tokens SET access_token, expiry_date, refresh_token
       WHERE user_id = <user>.
3. Proceed to insert events with the fresh access_token.
Mid-flight retry on 401/403: If a Google Calendar API call fails with HTTP 401 or 403 during event insertion (e.g., the token was silently invalidated between the pre-flight check and the API call), and a refresh_token is available, the function performs a second full refresh, updates the user_calendar_tokens row in the database, and retries the failing event once. If the retry also fails, the error is propagated and the entire request returns 500.
If Google issues a new refresh_token during either refresh cycle (uncommon but possible when access_type=offline is set without prompt=consent), the new value replaces the old one in user_calendar_tokens. If Google does not return a new refresh_token, the existing stored value is preserved.

Database table: user_calendar_tokens

The function reads from and writes to a single Supabase table. The Supabase client is created with the user’s JWT in the Authorization header so that RLS policies apply automatically.
ColumnTypeDescription
user_iduuidForeign key to the Supabase auth.users table. Used as the lookup key.
access_tokentextCurrent Google OAuth2 access token.
refresh_tokentext?Google OAuth2 refresh token. May be null if the OAuth flow did not return one.
expiry_datetext?ISO 8601 datetime string representing when access_token expires.
The corresponding TypeScript type used inside the function is:
type CalendarTokenRow = {
  user_id: string;
  access_token: string;
  refresh_token: string | null;
  expiry_date: string | null;
};
Populate user_calendar_tokens during your Google OAuth2 callback handler. Store the access_token, refresh_token, and compute expiry_date as new Date(Date.now() + expires_in * 1000).toISOString(). A missing or null refresh_token will block silent re-authentication and force the user to reconnect Google Calendar.

Build docs developers (and LLMs) love