Volver al blog
Desarrolladores

Consultar una plantilla de WhatsApp por nombre: GET /templates/by-name en Waspy

GET /api/v2/templates/by-name/:name devuelve la plantilla por el nombre que después mandás en POST /messages. Scope templates:read. Solo status approved se envía. No hay POST /templates.

· 11 min
Consultar una plantilla de WhatsApp por nombre: GET /templates/by-name en Waspy

Respuesta corta: si tu integración ya tiene el nombre de la plantilla y no el UUID, el pedido es GET https://api.waspytech.com/api/v2/templates/by-name/:name con Authorization: Bearer wspy_... y el scope templates:read. Los query opcionales son language y phoneNumberId. La respuesta trae la fila más nueva que matchea. Solo status: "approved" se puede enviar. POST /api/v2/templates no existe.

El listado paginado está en listar plantillas. El envío, en enviar una plantilla. La referencia pública está en templates. Donde esa página dice “nombre aprobado” y el handler no filtra el estado, abajo va lo que hace apps/api/src/routes/v2/templates.ts.

La clave pública entra en Scale (US$150 por mes) y Enterprise. Starter y Growth no la incluyen. Los planes están en Planes y el módulo, en la API.

Los tres GET, y para qué sirve cada uno

PedidoCuándo lo usás
GET /templates?status=approvedAuditoría: todas las que se pueden mandar, de a páginas
GET /templates/by-name/:nameEl CRM guarda pedido_despachado y necesita el estado y las variables
GET /templates/:idYa tenés el UUID interno (el id de una respuesta anterior)
Los tres piden templates:read. Una clave sin lista de scopes entra a todo. Si la lista existe y le falta ese scope, es 403 FORBIDDEN. Los scopes están en scopes.

El listado pagina con page (default 1) y pageSize (default 20, máximo 100), y acepta status y phoneNumberId. language no filtra el listado. by-name es una sola fila: no trae page ni total.

Consultar por nombre

curl -sS "https://api.waspytech.com/api/v2/templates/by-name/pedido_despachado?language=es_AR" \
  -H "Authorization: Bearer $WASPY_API_KEY"
{
  "data": {
    "id": "template-uuid",
    "phoneNumberId": "channel-uuid",
    "metaTemplateId": "1234567890",
    "name": "pedido_despachado",
    "language": "es_AR",
    "category": "UTILITY",
    "status": "approved",
    "components": [
      { "type": "BODY", "text": "Hola {{1}}, tu pedido {{2}} ya salió. Seguimiento: {{3}}." }
    ],
    "createdAt": "2026-10-02T13:00:00.000Z"
  },
  "meta": { "requestId": "..." }
}
CampoPara qué
nameEl string de template.name en POST /messages
languageTiene que coincidir con template.language.code del envío
statuspending, approved, rejected, disabled o paused
componentsHEADER, BODY, FOOTER, BUTTONS. Ahí están las {{1}}
categoryMARKETING, UTILITY o AUTHENTICATION: es lo que factura Meta
idUUID de Waspy, para el GET /templates/:id de después
metaTemplateIdEl id del lado de Meta, para cruzarlo con Business Manager
phoneNumberIdCanal, o null si la plantilla es global
El handler ordena por createdAt descendente y se queda con una fila. No exige status = approved. Si cargaste el mismo nombre dos veces, ves la más nueva, que puede seguir en pending mientras la anterior ya estaba approved. Por eso el if del envío mira data.status, no solo el 200.
const name = 'pedido_despachado';
const url = new URL(
  'https://api.waspytech.com/api/v2/templates/by-name/' + encodeURIComponent(name),
);
url.searchParams.set('language', 'es_AR');
url.searchParams.set('phoneNumberId', process.env.WASPY_CHANNEL_ID);

const res = await fetch(url, {
  headers: { Authorization: 'Bearer ' + process.env.WASPY_API_KEY },
});
if (res.status === 404) {
  throw new Error('TEMPLATE_NOT_FOUND');
}
if (!res.ok) {
  throw new Error('Waspy ' + res.status);
}
const { data } = await res.json();
if (data.status !== 'approved') {
  // pending, rejected, paused o disabled: no encolar el POST /messages
  throw new Error('plantilla ' + data.status);
}

phoneNumberId del query tiene que ser un UUID. Si pasás el id de teléfono de Meta, el schema responde 400 VALIDATION_ERROR. El UUID del canal sale de GET /api/v2/channels.

Si no hay fila con ese nombre (y ese idioma o canal, cuando los pasaste), es 404 TEMPLATE_NOT_FOUND. Un UUID de otra cuenta en GET /templates/:id es el mismo 404: no es un 403 que diga “es de otro tenant”.

Por id, cuando ya lo tenés

curl -sS "https://api.waspytech.com/api/v2/templates/TEMPLATE_UUID" \
  -H "Authorization: Bearer $WASPY_API_KEY"

El id del path es UUID. Un slug o el metaTemplateId no pasan el schema: 400 VALIDATION_ERROR. El JSON es el mismo objeto que by-name. Este GET tampoco filtra por approved.

Qué no hace este recurso

QuerésQué hay
Crear, editar o borrar por RESTNo. No hay POST /api/v2/templates
Alta de una plantilla de textoPanel, o MCP create_template con templates:write
Refrescar el estado desde MetaMCP get_template_status (templates:read). El GET REST lee la copia local
Webhook template.approvedNo existe
EnviarOtro pedido: POST /api/v2/messages, scope messages:write
create_template valida el cuerpo (variables en orden, sin promo dentro de una utilidad) y lo manda a revisión. No le escribe a ningún cliente y no es un endpoint de /api/v2. La guía del conector está en conectar MCP.

La página de templates avisa que un envío con una plantilla que no está approved recibe un error de Meta. El POST /messages de la v2 encola por nombre: buildTemplateContent busca la definición local para armar el texto y no rechaza un pending antes de la cola. El filtro lo hacés vos, con este GET, antes de encolar. Cómo queda el 201 está en enviar una plantilla.

Cada cuánto consultar

La API v2 permite 120 pedidos por minuto por cuenta. Lo comparten todas las claves. Un loop de by-name sin pausa se come el cupo que también usa el POST /messages. Una pasada antes del envío del día, o cada varios minutos mientras Meta revisa, alcanza.

Qué cobra Meta si el status es approved

El category del JSON es el que factura, por mensaje entregado, al país del destinatario. En Argentina, desde el 1 de octubre de 2026:

categoryDólaresPesos
MARKETINGUS$0,0618ARS 89,56
UTILITYUS$0,026ARS 37,68
AUTHENTICATIONUS$0,026ARS 37,68
Waspy no suma un markup. La fuente es la rate card. El desglose está en cuánto cuesta la API. Un cupón dentro de pedido_despachado puede dejar de ser UTILITY: mirá el category que devolvió el GET.

Errores de esta llamada

HTTPerror.codeCuándo
401UNAUTHORIZEDFalta el header, o la clave no existe
403FORBIDDENLa clave tiene scopes y no incluye templates:read
404TEMPLATE_NOT_FOUNDEl nombre o el UUID no están en tu cuenta
400VALIDATION_ERRORphoneNumberId que no es UUID, o un :id que no es UUID
429RATE_LIMITEDMás de 120 pedidos por minuto en la cuenta
Diez días de prueba, sin tarjeta, en el registro. La API se habilita en Scale y Enterprise.

Tu equipo atendiendo por WhatsApp en minutos

CRM facil pero potente. En 10 minutos tenes a tu equipo trabajando — no necesitas hablar con nadie.