> ## Documentation Index
> Fetch the complete documentation index at: https://docs.waspytech.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Limitaciones conocidas

> Lo que la API v2 todavía NO soporta — para que puedas planear tu integración con datos reales.

Esta página existe para que sepas exactamente qué se puede y qué no se puede hacer hoy con la API pública. Si algo de lo siguiente es bloqueante para vos, [contactanos](https://waspytech.com).

## Webhooks

* **Sin streaming / WebSocket público.** Si necesitás latencia sub-segundo, hablá con nosotros.
* **Eventos de templates no implementados todavía.** No existe `template.approved` / `template.rejected`. Mientras tanto, polleá `GET /templates` o `GET /templates/by-name/:name`.
* **Replay de delivery histórico:** el endpoint `POST /webhooks/:id/replay/:deliveryId` re-fires un evento sintético del mismo `event` name. El payload original no se almacena verbatim (solo su hash), por eso tu integración debe ser idempotente sobre `data.id`.
* **`POST /webhooks/:id/test` simula un `message.received`** con datos dummy. La response incluye `samplePayload` con el envelope exacto que se entrega.

## Mensajes

* **Templates** se pueden enviar y consultar pero no crear/editar/borrar vía API. Usá el panel de Waspy o Meta Business Manager.
* **Campañas** no tienen endpoints v2 todavía (existen vía API interna del panel).
* **Reacciones** outbound no están soportadas vía API.

## Media

* **Upload vía API v2 no está expuesto todavía.** Para enviar media, pasá `link` (URL pública) o `id` (media ID de Meta) en el body de `POST /messages`. La descarga inbound vía `GET /media/:id` sí funciona.
* Si tu integración necesita subir blobs (imágenes generadas en runtime, audios) y no tenés CDN propio, esto es un gap. Avisanos.

## Conversations

* **Typing `off`** se acepta pero no manda nada a Meta — Meta no soporta apagar manualmente el typing (se auto-clarea \~25s).
* **Mark-as-read** marca la última inbound con `waMessageId` por conversación. Si necesitás marcar un mensaje específico, usá `POST /messages/:waMessageId/read`.

## Origin tracking

* Para mensajes anteriores a abril 2026, `origin` se deriva de campos legacy. Ver [Handoff: legacy fallback](/concepts/handoff#origin-para-mensajes-pre-abril-2026-legacy-fallback) para los criterios exactos.
* Para mensajes nuevos siempre se setea explícitamente vía `metadata.origin`.

## Schemas

* **`WebhookEventEnvelope.data` y `Message.content` son `unknown`** en el OpenAPI spec (no discriminated union por evento/tipo). El payload real sí tiene shape definida — ver [catálogo de eventos](/webhooks/events) y los ejemplos por tipo en [Messages](/api-reference/messages). Pendiente: tipar discriminated union para que clientes de TypeScript inferieran sin asumir.

## Rate limits

* **120 req/min por API key** (no por canal). Si tenés múltiples números bajo la misma cuenta, comparten cuota — para cuotas independientes hoy hay que tener API keys separadas.
* **80 mensajes/seg por número** (límite Meta, no de Waspy).

## Errores de servidor

A partir de abril 2026 los errores 5xx se serializan SIEMPRE como `{ error: { code: "INTERNAL_ERROR", message: "Internal server error" } }`. Códigos internos (ej. SQLSTATE de PostgreSQL como `23503`) **no se filtran** al cliente. El detalle se loggea server-side bajo `originalCode` para que ops pueda diagnosticar.

## Resiliencia y reintentos del integrador

Waspy corre sobre Cloud Run con auto-scaling. Esto significa que **vas a recibir respuestas transitorias 503 ocasionales** durante:

* Despliegues (rolling restart de instancias)
* Cold starts cuando el tráfico salta de 0 instancias activas
* Caídas momentáneas de la conexión a la DB

**Recomendación obligatoria para tu integración:**

1. **Implementá retry con backoff exponencial** ante 503, 429 y errores de red. Sugerencia: `[1s, 2s, 4s, 8s]` con jitter.
2. **Para `POST /messages`** usá el header `Idempotency-Key` para que los retries no generen duplicados.
3. **Si recibís 429**, respetá el header `Retry-After` (segundos hasta que se libera tu rate limit).
4. **Después de 4-5 intentos fallidos**, escalá a alerta — probable incidente del lado nuestro.

Ejemplo de wrapper en TypeScript:

```ts theme={null}
async function sendWithRetry(body: unknown, idempotencyKey: string) {
  const delays = [1000, 2000, 4000, 8000];
  for (const delay of [...delays, null]) {
    const res = await fetch('https://api.waspytech.com/api/v2/messages', {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${WASPY_KEY}`,
        'Content-Type': 'application/json',
        'Idempotency-Key': idempotencyKey,
      },
      body: JSON.stringify(body),
    });
    if (res.ok) return res.json();
    if (res.status < 500 && res.status !== 429) return res.json(); // 4xx no-retryable
    if (delay === null) throw new Error('Max retries exhausted');
    const retryAfterSec = parseInt(res.headers.get('Retry-After') || '0', 10);
    await new Promise(r => setTimeout(r, retryAfterSec ? retryAfterSec * 1000 : delay));
  }
}
```

## Service window helper

Hoy el campo `serviceWindowExpiresAt` aparece dentro de cada `ConversationPublic` (response de `GET /conversations/:id` y de la lista). NO existe todavía un endpoint corto tipo `GET /contacts/:id/can-send-text`. Si tu integración necesita decidir entre texto libre vs template antes de enviar, hacé `GET /conversations/by-phone/:phone` y leé `serviceWindowExpiresAt`.

## Sandbox / test mode

No existe un canal sandbox que sea no-op. Cualquier mensaje que envíes desde tu integración llega al usuario real de WhatsApp. Para desarrollo seguro:

* Usá un número WhatsApp de test (Meta provee uno gratis al crear app)
* O un número personal tuyo como `to`
* `POST /webhooks/:id/test` SÍ es un sandbox para probar la firma + URL sin generar mensaje real

## Cloud Run 503 sin envelope JSON

Cuando Cloud Run rota una instancia o tiene cold start, devuelve **`503 Service Unavailable`** con body `text/html` (no nuestro envelope JSON `{ error: { code, message } }`). El integrador debe distinguir 503 con `Content-Type: text/html` (Cloud Run, retry) vs 5xx con `application/json` (app, ver mensaje).

## Lo que sí está cubierto

Account, Channels, Contacts, Conversations (read/typing/mark-as-read), Messages (incluye `origin` para handoff), Templates (lectura + by-name), Media (descarga), Webhooks (CRUD + deliveries + rotate-secret + test + replay).

Si algo no está documentado y lo necesitás para tu integración, decinos.
