Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/shadownrx/apisquare/llms.txt

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

Vercel KV is ApiSquare’s primary data store in production. It is Redis-compatible and accessed through the @vercel/kv package (version ^3.0.0). When the KV_REST_API_URL and KV_REST_API_TOKEN environment variables are absent — as they typically are during local development — the app falls back to in-memory Node.js globals, so you can run and test the bot without any external infrastructure.

Setting up Vercel KV

1

Create a KV database in the Vercel dashboard

Open your project in vercel.com, navigate to the Storage tab, and click Create Database. Choose KV (powered by Upstash) and complete the creation wizard.
2

Link the database to your project

Once the database is created, Vercel will prompt you to connect it to one or more projects. Select your ApiSquare project and confirm. This automatically injects the required environment variables into your Vercel deployment.
3

Pull the environment variables locally

Run the following command from the root of your project to sync the KV credentials into your local .env.local file:
vercel env pull .env.local
4

Verify the variables are present

Open .env.local and confirm these two variables exist:
KV_REST_API_URL=https://<your-kv-endpoint>.kv.vercel-storage.com
KV_REST_API_TOKEN=<your-rest-api-token>
ApiSquare reads both at startup. If either is missing the app silently falls back to in-memory storage.

KV client initialization

The KV client is created once per module and guarded by a try/catch so that a missing configuration never crashes the server at import time:
import { createClient } from '@vercel/kv';

let kv: any = null;
try {
  if (process.env.KV_REST_API_URL && process.env.KV_REST_API_TOKEN) {
    kv = createClient({
      url: process.env.KV_REST_API_URL,
      token: process.env.KV_REST_API_TOKEN,
    });
  }
} catch (e) {
  console.log('KV not available locally, using memory storage');
}
The kv variable is null when the env vars are absent. Every function that needs persistence checks if (kv) before calling KV and falls through to the in-memory equivalent otherwise.

Key schema

The table below lists every KV key pattern used across the codebase, along with its value type, expiry policy, and purpose.
Key PatternTypeTTLPurpose
app:configJSON objectNoneBot configuration — professionals, schedules, services, and holidays
conv:{chatId}JSON objectNoneActive multi-step conversation state for a Telegram user
reserva:{prof}:{date}:{time}JSON object30 daysReservation record indexed by slot (professional + date + time)
reserva:id:{id}JSON object30 daysSame reservation record indexed by its unique ID for O(1) lookups
user:{chatId}:reservasJSON arrayNoneOrdered list of all active reservations belonging to a user
session:{token}string "1"7 daysAdmin session token used to protect the /admin routes
ratelimit:user:{chatId}JSON object60 secondsPer-user message rate-limit counter (max 20 messages per window)
ratelimit:login:{ip}JSON object15 minutesLogin brute-force counter to protect the admin login endpoint
processed:update:{updateId}string "1"600 secondsWebhook deduplication — prevents double-processing the same Telegram update
The user:{chatId}:reservas list is self-healing: when the bot loads a user’s reservations it cross-checks each entry against reserva:id:{id}. Any entry whose corresponding slot key no longer exists is silently removed and the list is rewritten, keeping it consistent even if reservation keys expired.

Local development fallback

When KV_REST_API_URL and KV_REST_API_TOKEN are not set, ApiSquare stores all runtime data in Node.js global variables that persist for the lifetime of the server process:
Global variableEquivalent KV data
global._localReservationsAll reservation objects (array)
global._localAppConfigBot configuration object
global._localSessionsAdmin session tokens
These globals are initialized on first access and exported as plain helper functions (getLocalReservations, addLocalReservation, getLocalConfig, setLocalConfig) so every route handler can read and write them without duplicating the null-guard logic.
In-memory data is lost on every server restart. Do not rely on the local fallback for anything beyond quick smoke tests. Always use a real Vercel KV database before testing booking flows end-to-end.

TTL management

Reservation keys (reserva:{prof}:{date}:{time} and reserva:id:{id}) are written with a 30-day expiry ({ ex: 86400 * 30 }). This means stale or past reservations are automatically evicted by Redis without requiring any maintenance job, cron task, or manual cleanup. The webhook deduplication keys expire after 600 seconds and rate-limit keys expire at the end of their respective windows, so those buckets are self-cleaning as well.
If you need reservations to live longer than 30 days — for example, to keep a historical audit log — increase the ex value in the guardarReserva function inside app/api/webhook/route.ts and add the same TTL to the reserva:id:{id} key written in the same call.

Build docs developers (and LLMs) love