VAPI Todo System

AI Voice agentic solution integrated with VAPI

Flask SQLAlchemy Pydantic VAPI Google Calendar

Technical Architecture

Overview

VAPI is currently the leading Voice AI agent solution for developers in the market. This project leverages VAPI to enable users to manage to-do tasks, reminders, and calendar events through natural voice interactions.
Callers can create, update, and delete their tasks, reminders, and events simply by speaking. All data is stored in a PostgreSQL database and seamlessly integrated with the user’s Google Calendar and Gmail via the Google Calendar API, ensuring real-time synchronization across platforms.

Core Technologies

  • • Flask (Python web framework)
  • • SQLAlchemy with shared database instance
  • • Pydantic models for request/response validation
  • • markdown2 for documentation rendering
  • • Blueprint architecture for modular design

Key Features

  • • Todo list management
  • • Reminder system
  • • Calendar event management
  • • Google Calendar integration
  • • Voice API integration
  • • RESTful API endpoints

Module Structure

Shared Components

shared/
├── google_calendar.py  # Google Calendar integration service
├── helpers.py          # Shared utility functions
└── schemas.py          # Pydantic validation schemas

VAPI Todo Components

vapi_todo/
├── __init__.py      # Package initialization, exports blueprint
├── models.py        # SQLAlchemy database models
├── routes.py        # Flask routes and blueprint definition
└── README_vapi.md   # Documentation

Data Layer (models.py)

Todo Model

  • • id: Primary key
  • • title: Task title (indexed)
  • • description: Optional task details
  • • completed: Boolean status
  • • google_calendar_event_id

Reminder Model

  • • id: Primary key
  • • reminder_text: Reminder content
  • • importance: Priority level
  • • google_calendar_event_id

CalendarEvent Model

  • • id: Primary key
  • • title: Event title (indexed)
  • • description: Event details
  • • event_from: Start datetime
  • • event_to: End datetime
  • • google_calendar_event_id

API Endpoints

Todo Management

  • POST /create_todo
  • POST /get_todos
  • POST /complete_todo
  • POST /delete_todo

Reminder Management

  • POST /add_reminder
  • POST /get_reminders
  • POST /delete_reminder

Calendar Management

  • POST /add_calendar_entry
  • POST /get_calendar_entries
  • POST /delete_calendar_entry

Response Format

All API responses follow a consistent structure:

{
    "results": [
        {
            "toolCallId": "string",
            "result": "success" | object | array
        }
            ]
    }

Google Calendar Integration

The VAPI Todo system integrates with Google Calendar to automatically sync calendar events, todos, and reminders with the user's Google Calendar account.

Authentication

  • • OAuth2 authentication with Google Calendar API
  • • Requires credentials.json from Google Cloud Console
  • • Token-based authentication with automatic refresh
  • • Supports desktop application authentication flow

Features

  • • Automatic event creation in Google Calendar
  • • Real-time synchronization with database
  • • Event updates and deletions
  • • Timezone-aware datetime handling

Implementation Details

Service Location: shared/google_calendar.py

Main Class: GoogleCalendarService

Global Access: get_calendar_service()

API Methods

  • create_event() - Create new calendar event
  • update_event() - Update existing event
  • delete_event() - Delete calendar event
  • get_event() - Retrieve event details

Code Examples

Database Models (models.py)

from extensions import db
from datetime import datetime

class VapiTodo(db.Model):
    __tablename__ = 'vapi_todos'
    
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(255), index=True)
    description = db.Column(db.Text)
    completed = db.Column(db.Boolean, default=False)
    created_at = db.Column(db.DateTime, default=datetime.utcnow)
    google_calendar_event_id = db.Column(db.String(255))

class VapiReminder(db.Model):
    __tablename__ = 'vapi_reminders'
    
    id = db.Column(db.Integer, primary_key=True)
    reminder_text = db.Column(db.String(500))
    importance = db.Column(db.String(50))
    created_at = db.Column(db.DateTime, default=datetime.utcnow)
    google_calendar_event_id = db.Column(db.String(255))

API Routes (routes.py)

from flask import Blueprint, request, jsonify
from shared.helpers import get_validated_tool_call
from .models import VapiTodo, VapiReminder
from shared.schemas import TodoResponse, ReminderResponse
from shared.google_calendar import get_calendar_service

vapi_flask_bp = Blueprint('vapi_todo', __name__, url_prefix='/vapi_todo')

@vapi_flask_bp.route('/create_todo', methods=['POST'])
def create_todo():
    tool_call = get_validated_tool_call('createTodo')
    args = tool_call.function.arguments
    title = args.get('title', '')
    description = args.get('description', '')
    
    # Create todo in database
    todo = VapiTodo(title=title, description=description)
    db.session.add(todo)
    db.session.commit()
    db.session.refresh(todo)
    
    # Sync with Google Calendar
    try:
        calendar_service = get_calendar_service()
        google_event_id = calendar_service.create_event(
            title=f"TODO: {title}",
            description=description or "Task from VAPI Todo System"
        )
        if google_event_id:
            todo.google_calendar_event_id = google_event_id
            db.session.commit()
    except Exception as e:
        print(f"Failed to sync with Google Calendar: {e}")
    
    return jsonify({'results': [{'toolCallId': tool_call.id, 'result': 'success'}]})

Shared Components

Helpers (shared/helpers.py)
from flask import request, abort
from pydantic import ValidationError as PydanticValidationError
from .schemas import ToolRequest, ToolCall

def get_validated_tool_call(expected_function_name: str) -> ToolCall:
    """
    Validates the incoming JSON request against the ToolRequest schema
    and returns the specific tool call matching the expected function name.
    """
    json_data = request.get_json()
    if not json_data:
        abort(400, description="Invalid JSON payload.")

    try:
        # Validate the entire request structure
        tool_req = ToolRequest(**json_data)
    except PydanticValidationError as e:
        abort(400, description=f"Invalid request format: {e.errors()}")

    # Find the specific tool call we are looking for
    for tool_call in tool_req.message.toolCalls:
        if tool_call.function.name == expected_function_name:
            # If arguments are a string, parse them into a dict
            if isinstance(tool_call.function.arguments, str):
                tool_call.function.arguments = request.json_loads(tool_call.function.arguments)
            return tool_call

    abort(400, description=f"Tool call with function name '{expected_function_name}' not found.")
Schemas (shared/schemas.py)
import datetime as dt
from typing import Union, Dict, Any
from pydantic import BaseModel, ValidationError as PydanticValidationError

# --- Common Schemas for Tool Calling ---

class ToolCallFunction(BaseModel):
    name: str
    arguments: Union[str, Dict[str, Any]]

class ToolCall(BaseModel):
    id: str
    function: ToolCallFunction

class Message(BaseModel):
    toolCalls: list[ToolCall]

class ToolRequest(BaseModel):
    """A generic request model for any tool-calling service."""
    message: Message

# --- Common Response Schemas ---

class TodoResponse(BaseModel):
    id: int
    title: str
    description: Union[str, None]
    completed: bool
    model_config = {'from_attributes': True}

class ReminderResponse(BaseModel):
    id: int
    reminder_text: str
    importance: str
    model_config = {'from_attributes': True}

class CalendarEventResponse(BaseModel):
    id: int
    title: str
    description: Union[str, None]
    event_from: dt.datetime
    event_to: dt.datetime
    model_config = {'from_attributes': True}

Google Calendar Integration

from shared.google_calendar import get_calendar_service
from datetime import datetime, timedelta

# Create calendar service
calendar_service = get_calendar_service()

# Create event in Google Calendar
google_event_id = calendar_service.create_event(
    title=f"Todo: {todo.title}",
    description=todo.description or "Task from VAPI Todo System",
    start_time=datetime.now(),
    end_time=datetime.now() + timedelta(hours=1)
)

# Store Google Calendar event ID
if google_event_id:
    todo.google_calendar_event_id = google_event_id
    db.session.commit()

VAPI Integration Guide

VAPI Configuration & Deployment

1. VAPI.AI Setup

Start by creating an account if you do not have an account and logging in.

2. Create Tool

Once logged in, go to your dashboard and click on "Create Tool" in Tools/Build of the left panel.

3. Tool Functions

Todo Functions
  • • createTodo
  • • getTodos
  • • completeTodo
  • • deleteTodo
Reminder Functions
  • • addReminder
  • • getReminder
  • • deleteReminder
Calendar Functions
  • • addCalendarEntry
  • • getCalendarEntries
  • • deleteCalendarEntry

4. Create Assistant

Model Configuration
  • • Provider: OpenAI or preferred
  • • Model: GPT 4o Cluster
  • • First Message: Customize as needed
Voice & Transcriber
  • • Voice Provider: OpenAI
  • • Transcriber: Deepgram
  • • Language: English
  • • Tools: Select created functions

5. Publish

Once creating an assistant and tools, click "published" to make it live.

API Functions Implementation

The Flask API responds to VAPI tool calls with validated requests:

tool_call = _get_validated_tool_call('createTodo')
# Make sure that attribute 'createTodo' name should exactly match 
# to 'Create Tool' name in step 3.
Database Requirements

Postgres DB need to be created and db.Model need to be set for each table.

Testing AI Voice Scheduler

1

Make a call and say "to do list with time and date" to AI assistant

2

Make a call and ask what "to do lists" exist currently and ask to remind the tasks

3

Make a call and say that some tasks were completed

4

Make a call and say that some tasks were deleted

5

Check whether all test cases have been updated to Database tables

Test Results & Validation

1. Create Todo Functionality

Database Validation
Todo Creation Database

ToDo Task created successfully in todos table

GMail Pop-up
Todo Creation Interface

Call Transcript
Create Todo Call Transcript

Voice interaction transcript for todo creation

Voice Recording

Voice call recording for todo creation

2. Add Reminders Functionality

Database Validation
Add Reminders Database

Reminder database entry created

GMail Pop-up
Add Reminder Interface

3. Add Calendar Events Functionality

Database Validation
Add Calendar Events Database

Calendar event database entry

Google Calendar Sync 1
Google Calendar Sync 1

Google Calendar integration

Google Calendar Sync 2
Google Calendar Sync 2

Additional calendar sync view

4. Complete Todo Functionality

Database Validation
Todo Task Completed Database

Task completion status in database

Call Transcript
Complete Todo Call Transcript

Voice interaction for task completion

Voice Recording

Voice call recording for task completion

5. Delete Calendar Event Functionality

Database Validation
Calendar Events Deleted Database

Calendar event deletion from database

Call Transcript
Delete Calendar Event Call Transcript

Voice interaction for calendar deletion

Google Calendar Sync
Google Calendar Deleted

One Event deletion from Google Calendar

Voice Recording

Voice call recording for calendar deletion