guaba·commerceConnect · guía técnica

Guaba Connect · contrato v1

Conectá tu ecommerce a WhatsApp en dos endpoints

Guaba atiende WhatsApp por el negocio: catálogo, agente con IA y pedidos. Con Connect, Guaba lee el catálogo de tu plataforma y le empuja los pedidos que se generan por WhatsApp — tu ecommerce sigue siendo la fuente de verdad. Esto es todo lo que hay que implementar.

Cómo funciona

1

Guaba lee tu catálogo

Consulta GET /catalogo cada pocos minutos. Productos, variantes, precios y stock — tu plataforma manda.

2

Guaba te empuja pedidos

Cuando un cliente confirma por WhatsApp, llega un POST /pedidos firmado. Respondés con tu ID de pedido.

3

Vos reportás estados

Confirmado, enviado, entregado… se lo avisás a Guaba para que el agente le responda al cliente.

Credenciales

El negocio las genera en su panel de Guaba (Configuración → Guaba Connect) y te las pasa. Se muestran una sola vez y se pueden rotar.

CredencialDirecciónPara qué
glt_… token de lecturaGuaba → vosHeader Authorization: Bearer en cada pull y push. Verificalo siempre.
gfs_… secreto de firmaGuaba → vosHMAC-SHA256 del cuerpo crudo en X-Guaba-Signature. Confirmá que el pedido viene de Guaba.
gak_… api keyvos → GuabaHeader X-Guaba-Api-Key al reportar estados de pedido.

1 · Tu catálogo — GET {base_url}/catalogo

Query params: page (desde 1), per_page (máx. 200) y updated_since (ISO-8601, opcional — si lo soportás, los sync son incrementales).

{
  "productos": [
    {
      "id": "SKU-123",
      "nombre": "Queque de zanahoria",
      "descripcion": "Para 8 personas",
      "precio": 8500,
      "moneda": "CRC",
      "imagen_url": "https://tu-tienda.com/img/queque.jpg",
      "categoria": "Queques",
      "disponible": true,
      "stock": 5,
      "variantes": [
        { "id": "SKU-123-P", "nombre": "pequeño", "precio": 4500, "stock": 2, "disponible": true },
        { "id": "SKU-123-G", "nombre": "grande",  "precio": 8500, "stock": null, "disponible": true }
      ]
    }
  ],
  "pagina": 1,
  "total_paginas": 3
}

2 · Tus pedidos — POST {base_url}/pedidos

Headers: Authorization: Bearer · X-Guaba-Signature: sha256=<hmac> · X-Guaba-Idempotency-Key: <uuid>

{
  "pedido_guaba_id": "9f2c1a37-4b2e-4c1d-9e8f-1a2b3c4d5e6f",
  "creado_en": "2026-07-10T14:03:00Z",
  "cliente": { "nombre": "Tania", "telefono": "+50663270771" },
  "items": [
    {
      "producto_id": "SKU-123",
      "variante_id": "SKU-123-G",
      "nombre": "Queque de zanahoria (grande)",
      "cantidad": 1,
      "precio_unitario": 8500
    }
  ],
  "total": 8500,
  "moneda": "CRC",
  "notas": "Retira el sábado 10am",
  "canal": "whatsapp"
}

// Tu respuesta esperada (201):
{ "pedido_id": "WC-4581" }

3 · Estados — POST …/api/connect/pedidos/{pedido_guaba_id}

Opcional pero recomendado: sin esto, el agente no puede contestarle al cliente en qué va su pedido. Header X-Guaba-Api-Key.

{ "estado": "confirmado", "pedido_id": "WC-4581" }

// estados válidos: confirmado · preparando · entregado · cancelado
// respuestas: 200 ok · 401 api key · 404 pedido · 422 estado inválido

Checklist de implementación

🤖 Implementalo con IA

¿Usás Claude, Cursor o Copilot? Copiá el prompt, pegalo en tu asistente junto con tu código, reemplazá los valores marcados con {{…}} y dejá que implemente tu lado del contrato. Cada prompt es autocontenido.

1 · Exponé tu catálogoGET /catalogo con Bearer y paginación, mapeando tu esquema de productos.
⚠️ ANTES DE PEGAR, REEMPLAZÁ ESTOS VALORES:
- {{TU_STACK}}: tu stack (ej: "Laravel 11 + MySQL", "Node/Express + Postgres", "WordPress/WooCommerce como plugin", "Django")
- {{URL_BASE}}: la URL base que vas a exponer (ej: https://mitienda.com/api/guaba)
- {{TOKEN_LECTURA}}: el token que te dio Guaba (empieza con glt_)
- {{SECRETO_FIRMA}}: el secreto de firma que te dio Guaba (empieza con gfs_)
- {{API_KEY}}: la api key que te dio Guaba (empieza con gak_)
Guardá los tres como variables de entorno/secretos, nunca en el código.

Sos un desarrollador senior. Implementá en mi proyecto ({{TU_STACK}}) un endpoint HTTP para integrarme con Guaba Commerce (una plataforma que atiende WhatsApp por mi negocio y necesita LEER mi catálogo).

## Qué construir

GET {{URL_BASE}}/catalogo

1. AUTENTICACIÓN: exigí el header `Authorization: Bearer {{TOKEN_LECTURA}}` (compará contra la variable de entorno; si no coincide, respondé 401 JSON). Usá comparación de strings de tiempo constante si el lenguaje lo permite.
2. QUERY PARAMS: `page` (entero desde 1, default 1), `per_page` (entero, máximo 200, default 100), `updated_since` (ISO-8601 opcional — si viene, devolvé solo productos modificados desde esa fecha; si no podés implementarlo fácil, ignoralo).
3. RESPUESTA 200 (Content-Type application/json), mapeando MI esquema de productos a EXACTAMENTE este formato:

{
  "productos": [
    {
      "id": "SKU-123",              // MI identificador estable y único (SKU o ID interno) — string
      "nombre": "Queque de zanahoria",   // requerido, máx 120 chars
      "descripcion": "Para 8 personas",  // opcional, máx 500
      "precio": 8500,               // requerido, número en la unidad menor ya resuelta (colones enteros para CRC)
      "moneda": "CRC",              // opcional, ISO-4217, default CRC
      "imagen_url": "https://...",  // opcional, URL absoluta https
      "categoria": "Queques",       // opcional, máx 80
      "disponible": true,           // opcional, default true — false lo oculta de WhatsApp
      "stock": 5,                   // opcional; null u omitido = no controlo stock
      "variantes": [                // opcional — presentaciones/tamaños con precio propio (lista PLANA, sin matriz de atributos)
        { "id": "SKU-123-P", "nombre": "pequeño", "precio": 4500, "stock": 2, "disponible": true }
      ]
    }
  ],
  "pagina": 1,
  "total_paginas": 3
}

## Criterios de aceptación
- Solo productos que quiero vender por WhatsApp (publicados/activos).
- Los `id` (producto y variante) son estables entre llamadas: Guaba me referencia pedidos con ellos.
- Paginación correcta: `total_paginas` real; página fuera de rango → `productos: []`.
- Sin el Bearer correcto → 401. Todo sobre HTTPS.
- Respuesta en menos de 8 segundos (Guaba corta ahí): si mi catálogo es lento, agregá caché de ~1 minuto.

Mostrame el código completo, dónde ubicarlo en mi proyecto y cómo probarlo con curl.
2 · Recibí los pedidos de WhatsAppPOST /pedidos con verificación de firma HMAC e idempotencia persistente.
⚠️ ANTES DE PEGAR, REEMPLAZÁ ESTOS VALORES:
- {{TU_STACK}}: tu stack (ej: "Laravel 11 + MySQL", "Node/Express + Postgres", "WordPress/WooCommerce como plugin", "Django")
- {{URL_BASE}}: la URL base que vas a exponer (ej: https://mitienda.com/api/guaba)
- {{TOKEN_LECTURA}}: el token que te dio Guaba (empieza con glt_)
- {{SECRETO_FIRMA}}: el secreto de firma que te dio Guaba (empieza con gfs_)
- {{API_KEY}}: la api key que te dio Guaba (empieza con gak_)
Guardá los tres como variables de entorno/secretos, nunca en el código.

Sos un desarrollador senior. Implementá en mi proyecto ({{TU_STACK}}) el endpoint que RECIBE los pedidos que Guaba Commerce genera por WhatsApp y los crea como pedidos reales en mi plataforma.

## Qué construir

POST {{URL_BASE}}/pedidos

1. AUTENTICACIÓN (dos capas, ambas obligatorias):
   a. Header `Authorization: Bearer {{TOKEN_LECTURA}}` → si no coincide, 401.
   b. Header `X-Guaba-Signature: sha256=<hex>` = HMAC-SHA256 del CUERPO CRUDO del request (los bytes exactos, ANTES de parsear el JSON) con la clave {{SECRETO_FIRMA}}. Calculá el HMAC del cuerpo recibido y comparalo con timing-safe equal → si no coincide, 401. OJO: necesitás acceso al raw body (en Express: express.raw o verify callback; en Laravel: $request->getContent()).
2. IDEMPOTENCIA (crítico): header `X-Guaba-Idempotency-Key: <uuid>`. Guardá la key con el ID del pedido creado (tabla o cache persistente). Si llega OTRA VEZ la misma key → respondé 201 con el MISMO pedido_id SIN crear un duplicado. Guaba reintenta ante timeouts hasta 5 veces.
3. CUERPO que recibís:

{
  "pedido_guaba_id": "9f2c1a37-4b2e-4c1d-9e8f-1a2b3c4d5e6f",  // UUID del pedido en Guaba
  "creado_en": "2026-07-10T14:03:00Z",
  "cliente": { "nombre": "Tania", "telefono": "+50663270771" },
  "items": [
    {
      "producto_id": "SKU-123",      // MI id (el que expuse en /catalogo)
      "variante_id": "SKU-123-G",    // solo si el producto tiene variantes
      "nombre": "Queque de zanahoria (grande)",
      "cantidad": 1,
      "precio_unitario": 8500
    }
  ],
  "total": 8500,
  "moneda": "CRC",
  "notas": "Retira el sábado 10am",
  "canal": "whatsapp"
}

4. Creá el pedido en MI sistema como «pendiente de pago/confirmación» (igual que un pedido telefónico — el pago NO viaja por acá), asociando cliente por teléfono si existe.
5. RESPUESTA 201: { "pedido_id": "WC-4581" } — MI identificador del pedido creado.
6. ERRORES: 4xx si el pedido es inválido (Guaba NO reintenta y lo marca para revisión humana) · 5xx solo ante fallas transitorias (Guaba SÍ reintenta).

## Criterios de aceptación
- Verificación de firma con el cuerpo CRUDO (un espacio de diferencia rompe el HMAC).
- Segunda llamada con la misma idempotency key NO crea segundo pedido y devuelve el mismo pedido_id.
- Producto_id inexistente en mi catálogo → 422 con mensaje claro (no 500).
- Respuesta en menos de 8 segundos.

Mostrame el código completo, la migración/tabla para las idempotency keys, y cómo probarlo con curl (incluí cómo generar la firma HMAC de prueba en una línea).
3 · Reportá los estados a GuabaEl hook que avisa a Guaba cuando tu pedido avanza (confirmado, entregado…).
⚠️ ANTES DE PEGAR, REEMPLAZÁ ESTOS VALORES:
- {{TU_STACK}}: tu stack (ej: "Laravel 11 + MySQL", "Node/Express + Postgres", "WordPress/WooCommerce como plugin", "Django")
- {{URL_BASE}}: la URL base que vas a exponer (ej: https://mitienda.com/api/guaba)
- {{TOKEN_LECTURA}}: el token que te dio Guaba (empieza con glt_)
- {{SECRETO_FIRMA}}: el secreto de firma que te dio Guaba (empieza con gfs_)
- {{API_KEY}}: la api key que te dio Guaba (empieza con gak_)
Guardá los tres como variables de entorno/secretos, nunca en el código.

Sos un desarrollador senior. Agregá a mi proyecto ({{TU_STACK}}) las llamadas que le avisan a Guaba Commerce cuando un pedido cambia de estado en mi plataforma, para que su agente de WhatsApp pueda responderle al cliente «tu pedido va en camino».

## Qué construir

Cada vez que un pedido QUE VINO DE GUABA cambie de estado en mi sistema (lo reconocés porque lo creó el endpoint /pedidos y guardaste su `pedido_guaba_id`), hacé:

POST https://guaba.tech/api/connect/pedidos/{pedido_guaba_id}
Headers: `X-Guaba-Api-Key: {{API_KEY}}` · `Content-Type: application/json`
Body: { "estado": "confirmado", "pedido_id": "WC-4581" }

- Estados válidos (mapeá los míos a estos 4): "confirmado" (acepté el pedido), "preparando" (en producción/armado), "entregado" (el cliente lo tiene), "cancelado".
- `pedido_id` es MI identificador (opcional pero recomendado).
- Respuestas: 200 ok · 401 api key mala · 404 el pedido no existe en Guaba · 422 estado inválido.

## Criterios de aceptación
- El hook se dispara SOLO para pedidos con pedido_guaba_id (los demás pedidos de mi tienda no llaman a Guaba).
- Ante error de red o 5xx: reintentá con backoff (o encolá) — no bloquees mi flujo de pedidos por esto.
- Ante 401/404/422: logueá y NO reintentes (es un error de datos, no transitorio).
- La api key vive en variables de entorno.

Mostrame dónde engancharlo en mi flujo de cambio de estado (observer/hook/señal según mi stack) y el código completo con manejo de errores.

¿Dudas o feedback del contrato?

Estamos validando la v1 con los primeros integradores — tu opinión la moldea.

Escribinos →