Volver al blog
Desarrolladores

Por qué Meta rechazó la plantilla: get_template_status, no el GET de Waspy

GET /api/v2/templates no trae rejectionReason: el schema lo recorta. El motivo lo devuelve la herramienta MCP get_template_status, que lee Meta.

· 11 min
Por qué Meta rechazó la plantilla: get_template_status, no el GET de Waspy

Respuesta corta: GET https://api.waspytech.com/api/v2/templates y GET /api/v2/templates/by-name/:name te dicen si la plantilla está rejected. No te dicen por qué. El schema público no incluye rejectionReason ni qualityScore, y el serializer de la v2 descarta esas claves aunque la fila las tenga. El motivo lo pedís con la herramienta MCP get_template_status (https://api.waspytech.com/mcp, scope templates:read), que lee Meta y actualiza la copia local. En el panel, el mismo texto está en la ficha de la plantilla.

La referencia del GET está en templates. El conector, en conectar MCP. Cómo se redacta para que no la rechacen está en por qué rechazan una plantilla.

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.

Qué devuelve el GET, y qué no

El handler lee la fila completa. La respuesta HTTP pasa por TemplatePublic. Ese objeto declara id, phoneNumberId, metaTemplateId, name, language, category, status, components y createdAt. Un z.object se queda con esas claves y tira el resto. Por eso el JSON de un rechazo se ve así, sin motivo:

{
  "data": {
    "id": "template-uuid",
    "phoneNumberId": "channel-uuid",
    "metaTemplateId": "1234567890",
    "name": "pedido_despachado",
    "language": "es_AR",
    "category": "utility",
    "status": "rejected",
    "components": [
      { "type": "BODY", "text": "Hola {{1}}, tu pedido {{2}} ya salió." }
    ],
    "createdAt": "2026-11-02T13:00:00.000Z"
  },
  "meta": { "requestId": "..." }
}

category en la base es minúscula (marketing, utility, authentication). La página de docs a veces la muestra en mayúscula. El valor que factura Meta es esa categoría, no el texto del motivo.

Lo que sí vesLo que el JSON público no trae
status: pending, approved, rejected, paused, disabledrejectionReason
components, con las {{1}}rejectionDetails (código, título, descripción del webhook)
category y languagequalityScore (GREEN, YELLOW, RED o null)
metaTemplateIdtenantId, syncedAt, cardImageKeys, optInProofMediaKey
Filtrar GET /templates?status=rejected lista las rechazadas. Sigue sin el texto. El listado, by-name y el GET por UUID comparten el mismo recorte. El contrato del listado está en listar plantillas y el de by-name, en consultar por nombre.

get_template_status

No es GET /api/v2/.... Es una herramienta del MCP. Con una API key:

curl -sS -X POST https://api.waspytech.com/mcp \
  -H "Authorization: Bearer $WASPY_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"get_template_status","arguments":{"name":"pedido_despachado","phoneNumberId":"CHANNEL_UUID"}}}'

CHANNEL_UUID es el id interno del número (GET /api/v2/channels), no el phone number id de Meta. El scope es templates:read. Si la clave tiene una lista de scopes y ese no está, la herramienta responde que la conexión no tiene el permiso. Los nombres están en scopes.

El result.structuredContent que arma el servidor trae:

CampoQué es
idUUID interno de Waspy
nameEl nombre en Meta
statusEl estado que devolvió Meta, mapeado a minúscula
languagePor ejemplo es_AR
categorymarketing, utility o authentication
rejectionReasonEl rejected_reason de Meta, o null si vino NONE o vacío
Esa llamada pega a Meta y escribe status, category, rejectionReason y syncedAt en la fila. No es una lectura de cache. Si metaTemplateId empieza con sandbox:, la herramienta dice que la plantilla no está en Meta y no refresca.

Nombre, id, y la fila que elige

Hace falta name o id. Si no mandás ninguno, el texto es Pasá el nombre o el id de la plantilla.

  • id puede ser el UUID de Waspy o el id de Meta (metaTemplateId).
  • name busca por nombre en la cuenta. phoneNumberId desambigua si el mismo nombre está en dos números.
  • La búsqueda por nombre no recibe idioma y no ordena. Si pedido_despachado existe en es_AR y en en_US, puede volver cualquiera de las dos. Pasá phoneNumberId y, si todavía hay dos idiomas en el mismo número, usá el id.

Si no hay fila, el texto es No encuentro esa plantilla en esta cuenta. No es el 404 TEMPLATE_NOT_FOUND del GET REST.

De dónde sale el texto del motivo

Hay dos escrituras, y no dejan el mismo string.

CaminoQué guarda en rejectionReason
Webhook de estado de plantillaEl código de Meta y, si vino una descripción distinta, esa descripción en la línea de abajo. También guarda rejectionDetails con reason, title y description
Sync del número, o get_template_statusSolo rejected_reason, pasado por normalizeMetaNone. No escribe rejectionDetails
NONE, vacío o ausente quedan en null. Si Meta aprueba o reincorpora la plantilla, el webhook pone rejectionReason y rejectionDetails en null. Un get_template_status posterior deja el motivo en null cuando Meta ya no manda uno.

qualityScore lo escribe el sync del número, desde quality_score.score. El panel lo muestra (verde, amarillo, rojo). get_template_status no lo devuelve y el GET REST tampoco.

Qué no hace esta llamada

QuerésQué hay
Crear o editar por RESTNo hay POST ni PATCH /api/v2/templates
Alta de textoPanel, o MCP create_template con templates:write. Valida variables y promo en una utilidad antes de llamar a Meta. No le escribe al cliente
Webhook template.rejected en la API públicaNo existe. Los eventos públicos son mensaje, estado de mensaje, conversación y contacto
Que Waspy le conteste al cliente porque la plantilla fue rechazadaNo. El equipo reescribe. Un asistente externo puede llamar a esta herramienta; el mensaje al cliente lo confirma una persona
Las reglas que create_template chequea (variable al inicio o al final, dos variables juntas, promo dentro de una utilidad) están en crear una plantilla con MCP. Cómo conectar Claude, Cursor, Codex o Grok está en el conector.

Qué cobra Meta cuando después sí sale

Leer el motivo no entrega un mensaje. Cuando la plantilla queda approved y la mandás, Meta cobra por mensaje entregado. En Argentina, desde el 1 de octubre de 2026:

CategoríaDólaresPesos
MarketingUS$0,0618ARS 89,56
Utilidad o autenticaciónUS$0,026ARS 37,68
Waspy no suma un markup. La fuente es la rate card. El desglose está en cuánto cuesta la API.

La API v2 permite 120 pedidos por minuto por cuenta. get_template_status además gasta una llamada a Meta por cada refresco. Una pasada cuando el panel muestra “rechazada” alcanza. Un loop por cada nombre del catálogo no.

Tu equipo atendiendo por WhatsApp en minutos

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