Overview
Processes push notifications from Google Cloud Pub/Sub when new emails arrive in Gmail. Uses the Gmail History API to fetch new messages and AI-powered extraction to identify and store financial transactions.Endpoint
Authentication
This endpoint is called by Google Cloud Pub/Sub. Authentication is performed via theAuthorization header with a Bearer token (OIDC token from Pub/Sub).
Request
Headers
Bearer token from Google Cloud Pub/Sub (OIDC token)
Must be
application/jsonRequest Body
Pub/Sub message wrapper containing base64-encoded Gmail notification:Pub/Sub message object
Base64-encoded JSON containing Gmail notification data
Decoded Message Data
The base64-decodedmessage.data contains:
Example Request
Response
Always returns200 OK to acknowledge receipt to Pub/Sub, even if processing fails internally.
Success Response
Status Codes
Successfully processed notification (or gracefully handled error)
Invalid payload structure (missing required fields)
Method not allowed (only POST accepted)
Internal server error (still returns OK for Pub/Sub acknowledgment)
Processing Flow
1. Notification Validation
- Decodes base64 message data
- Extracts
emailAddressandhistoryId - Checks for duplicate processing using in-memory set
2. Token Resolution
- Queries
user_oauth_tokenstable for all active tokens matching the Gmail address - Validates each token by ensuring fresh access tokens
- Filters out tokens that require reconnection
3. History API Query
Fetches new messages using Gmail History API:4. Message Filtering
- Filters for messages with
INBOXlabel - Excludes messages in
SPAMorTRASH - Processes only the latest new message
5. Message Retrieval
Fetches full message details:6. Content Extraction
Extracts from message payload:- Subject - From
Subjectheader - From - Sender email address from
Fromheader - Date - Timestamp from
Dateheader - Body - Plain text or HTML body (stripped of tags)
- Attachments - Images (JPEG, PNG) and PDF documents
7. AI Transaction Analysis
CallsextractTransactionFromEmail() with:
- Email body text
- User’s full name (for personalized analysis)
- Image attachments (receipts, invoices)
- PDF text content (extracted documents)
8. Transaction Storage
If AI detects a transaction, stores intransactions table:
9. Duplicate Handling
If transaction already exists (duplicatesource_message_id), logs and continues without error.
10. Discarded Emails
If no transaction detected, stores indiscarded_emails table:
11. Fallback Processing
If AI processing fails, uses keyword-based detection: Keywords: purchase, payment, charge, debit, credit, invoice, receipt, $, €, £ If keywords found, creates a placeholder transaction with:- Amount: 0
- Currency: USD
- Type: expense
- Description: Email subject
- Category: uncategorized
12. History ID Update
Updatesgmail_watches table with the new history ID for the next notification.
Multi-User Support
The webhook processes notifications for all users who have connected the same Gmail account:- Finds all active tokens for the Gmail address
- Validates each token independently
- Creates separate transaction records for each user
- Handles token failures gracefully (disconnects invalid tokens)
Error Handling
Token Reconnection Required
When a token cannot be refreshed:- Deactivates the token in
user_oauth_tokens - Creates system notification for the user
- Continues processing for other valid tokens
- Returns 200 OK to Pub/Sub
Gmail API Errors
When Gmail API calls fail:- Logs error details
- Creates system notification with error details
- Returns 200 OK to Pub/Sub (to prevent retries)
AI Processing Errors
When AI extraction fails:- Falls back to keyword-based detection
- Creates transaction if keywords found
- Otherwise, discards email with reason
Notifications Created
System notifications are created for:gmail_sync_error- When Gmail API calls fail- (Notifications are sent with deduplication to avoid spam)
Notification Parameters
Implementation Details
Environment Variables Required
SUPABASE_URL- Supabase project URLSUPABASE_SERVICE_ROLE_KEY- Service role key for database access
In-Memory Deduplication
Uses aSet<string> to track processed {emailAddress}-{historyId} pairs and avoid duplicate processing within the function instance lifetime.
Deduplication is in-memory and resets when the function cold-starts. Database uniqueness constraints provide persistent deduplication.
Attachment Processing
Supports:- Images: JPEG, PNG (passed to AI vision for receipt/invoice analysis)
- PDFs: Text extraction via
unpdflibrary (text passed to AI)
AI Analysis
Uses Langfuse for observability. Flushes events before returning response:Related Functions
- auth-callback - Sets up Gmail watches that trigger this webhook
- renew-watches - Renews watches to keep notifications flowing
- process-document - Similar AI processing for manually uploaded files