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.

The /api/webhook endpoint is the heart of ApiSquare — Telegram delivers all bot updates here as POST requests. The handler processes both plain text messages and inline-keyboard callback queries, maintaining per-user conversation state in Vercel KV so multi-step booking flows survive across separate Telegram messages. No authentication is required; Telegram calls this endpoint directly on your behalf.

POST /api/webhook

Telegram sends a JSON-encoded Update object in the request body every time a user interacts with the bot.

Processing Pipeline

The handler executes the following steps in order on every incoming update:
  1. Deduplication — checks update_id against a KV key (processed:update:{update_id}) with a 10-minute TTL to skip replayed updates. Falls back to an in-memory Set when KV is unavailable.
  2. Rate limiting — enforces a per-user limit of 20 messages per 60-second window based on the chat.id extracted from either the message or callback_query field.
  3. Routing — dispatches to the callback-query handler if update.callback_query is present, otherwise to the text-message handler.
  4. Reply — sends responses to the user via the Telegram Bot API using sendMessage or answerCallbackQuery.
  5. Always 200 OK — returns {"status":"ok"} regardless of outcome.

Request Body

Telegram delivers a message update when the user sends text:
{
  "update_id": 123456789,
  "message": {
    "message_id": 1,
    "chat": { "id": 987654321 },
    "text": "/start"
  }
}
Telegram delivers a callback_query update when the user taps an inline keyboard button:
{
  "update_id": 123456790,
  "callback_query": {
    "id": "abcdef123456",
    "message": { "chat": { "id": 987654321 } },
    "data": "reservar"
  }
}
update_id
number
required
Telegram’s monotonically increasing update identifier. Used by the deduplication layer to skip already-processed updates within a 10-minute window.
message
object
Present on text/command updates. Must contain at least message.chat.id and message.text.
callback_query
object
Present on inline-button tap updates. Must contain callback_query.id, callback_query.message.chat.id, and callback_query.data.

Response

The endpoint always returns HTTP 200:
{ "status": "ok" }
The webhook always returns HTTP 200 {"status":"ok"} — even when an internal error occurs. This prevents Telegram from retrying the same update, which would cause duplicate messages or duplicate bookings.

GET /api/webhook — Verification Endpoint

Returns HTTP 200 {"status":"ok"} immediately. This route exists so that Telegram (and any infrastructure probe) can verify the webhook URL is reachable before sending live updates. Request
curl https://your-app.vercel.app/api/webhook
Response — HTTP 200 OK
{ "status": "ok" }

Supported Text Commands

The message handler normalises incoming text to lowercase and trims whitespace before matching. The following inputs are recognised as top-level intents:
Command / TextAction
/start, start, hola, hello, buenos días, buenas tardes, buenas noches, heyClear conversation state, show main menu
/servicios, servicios, servicio, /categorias, categorias, categoria, que servicios hayList all available services with prices
/misreservas, mis reservas, misreservas, reservas, ver reservas, ver mis reservasShow the user’s active reservations
/reservar, reservar, reservar turno, quiero reservar, agendar, quiero agendar, hacer una reservaBegin the multi-step booking flow
Any message that does not match a top-level intent and does not correspond to an active conversation step also falls back to showing the main menu.

Rate Limiting

ApiSquare enforces a per-user rate limit to protect against abuse and excessive KV reads.
ParameterValue
Maximum requests20 messages
Window duration60 seconds
ScopePer chat.id
KV keyratelimit:user:{chatId}
KV TTL60 seconds
When a user exceeds the limit:
  • If the triggering update is a callback query, Telegram receives an answerCallbackQuery call with the warning text ⚠️ Demasiadas solicitudes. Esperá un momento.
  • If it is a text message, the bot sends ⚠️ Estás enviando demasiados mensajes. Por favor esperá un momento antes de continuar.
In both cases the handler returns HTTP 200 {"status":"ok"} immediately after responding.
The chatId used for rate limiting is extracted from whichever field is present in the update: update.message.chat.id for text messages or update.callback_query.message.chat.id for inline-button taps.

Conversation State

ApiSquare maintains multi-step booking state in Vercel KV under the key conv:{chatId}. State is a JSON object of type ConversationState:
{
  "paso": "nombre",
  "profesional": "Francisco Chibilisco",
  "servicio": "Sesión de Quiropraxia",
  "nombre": null,
  "fecha": null,
  "hora": null
}
The paso field drives the state machine. Recognised values are: profesional, servicio, nombre, fecha, hora, and confirmar. Sending /start (or any greeting) clears this state entirely, restarting the flow.

Environment Variables

Set TELEGRAM_TOKEN in your environment variables before deploying. Without it, the bot cannot call sendMessage or answerCallbackQuery, so all updates will be silently dropped (the webhook will still return 200 OK to Telegram).
VariableRequiredDescription
TELEGRAM_TOKEN✅ YesBot token from @BotFather. Used for all Telegram Bot API calls.
KV_REST_API_URLRecommendedVercel KV REST endpoint. Required for persistent state, deduplication, and rate limiting across serverless invocations.
KV_REST_API_TOKENRecommendedAuth token for the Vercel KV REST API. Must be paired with KV_REST_API_URL.
When KV credentials are absent, the handler falls back to in-process memory storage — suitable for local development but not for production, since memory is not shared across serverless function instances.

Build docs developers (and LLMs) love