APIs Personalizadas
Cualquier endpoint HTTP puede convertirse en una herramienta. Describes la petición estilo Postman, declaras qué variables la rellenan, y Platica deriva de ahí el esquema que ve el modelo.
El modelo mental
Una API personalizada tiene dos partes:
request— la petición HTTP a ejecutar. Método, URL, headers, body y autenticación. Donde quieras un valor dinámico, escribes{{nombre}}.variables— quién rellena cada{{nombre}}. El campomodedecide el origen:
mode | Quién aporta el valor | ¿La ve el modelo? |
|---|---|---|
ai (default) | El modelo lo escribe al llamar la herramienta | Sí, aparece en el esquema |
constant | Valor fijo en constantValue | No |
context | Se toma de la conversación, según contextField | No |
El JSON Schema que recibe el modelo se deriva de las variables en modo ai al habilitar la herramienta. Nunca lo escribes a mano, y por eso la description de cada variable importa: es literalmente lo que el modelo lee para decidir qué mandar.
El ciclo de vida
draft ──enable──> enabled ──pause──> paused ──enable──> enabled Sólo en enabled la herramienta tiene una entrada en el catálogo del workspace y se le puede conectar a un agente. En draft y paused la configuración existe pero nadie la ve.
El integrationId y el toolId del catálogo son el mismo identificador, así que al habilitarla ya puedes usarlo en POST /v1/agents/{agentId}/tools .
Las llamadas sólo pueden resolver a direcciones públicas. Platica bloquea localhost, redes privadas, link-local, metadata de nube y redirecciones hacia esos destinos, tanto en pruebas como durante la ejecución del agente.
Listar APIs
GET https://api.platica.mx/v1/tools/apis Respuesta
{
"count": 1,
"apis": [
{
"id": "RuzoaswTBBrhutHyKYZn",
"name": "order_lookup",
"toolName": "api_order_lookup",
"description": "Consulta el estado de un pedido por su folio.",
"status": "enabled",
"method": "GET",
"url": "https://api.tienda.com/orders/{{orderId}}",
"variableCount": 1,
"lastTestOutcome": "success",
"lastTestAt": "2026-07-12T09:15:22.109Z",
"createdAt": "2026-07-10T15:41:03.902Z",
"updatedAt": "2026-07-12T09:18:44.117Z"
}
]
} | Campo | Tipo | Descripción |
|---|---|---|
name | string | Nombre corto que definiste. |
toolName | string | Nombre completo que ve el modelo: siempre api_<name>. |
status | string | draft, enabled o paused. |
variableCount | number | Total de variables, incluyendo las ocultas al modelo. |
lastTestOutcome | string | null | Resultado de la última prueba: success, http-error, network-error, schema-error o mapping-error. |
Crear API
Crea la herramienta como borrador. No queda disponible para ningún agente hasta habilitarla.
POST https://api.platica.mx/v1/tools/apis Cuerpo de la solicitud
{
"name": "order_lookup",
"description": "Consulta el estado de un pedido de la tienda por su folio. Úsala cuando el cliente pregunte dónde va su pedido.",
"request": {
"method": "GET",
"url": "https://api.tienda.com/orders/{{orderId}}",
"headers": [
{ "key": "Accept", "value": "application/json" }
],
"auth": {
"type": "bearer",
"token": "sk_live_xxx"
}
},
"variables": [
{
"name": "orderId",
"type": "string",
"description": "Folio del pedido, tal como aparece en el correo de confirmación.",
"required": true
}
],
"response": {
"path": "data",
"exclude": ["internal_notes"]
}
} | Parámetro | Tipo | Descripción | Requerido |
|---|---|---|---|
name | string | Minúsculas, empieza con letra o dígito, sólo letras, dígitos y _ (≤ 62 caracteres). El modelo la verá como api_<name> | ✓ |
description | string | Entre 10 y 1024 caracteres. Explica cuándo debe llamarla el agente | ✓ |
request | objeto | La petición HTTP. Ver abajo | ✓ |
variables | array | Qué rellena cada {{nombre}}. Máximo 50 | — |
passContext | boolean | Necesario para usar variables en modo context | — |
context | objeto | { "lastMessagesN": 10 } — cuántos mensajes expone {{ctx.lastMessages}} | — |
mapping | objeto | bodyStrategy (merge, replace, none) y extraBody con pares fijos | — |
response | objeto | Recorte de la respuesta antes de dársela al modelo | — |
periodicAuth | objeto | Inyecta un token obtenido por un cron job | — |
encryptPayload | objeto | Firma el body saliente como JWT | — |
{
"method": "POST",
"url": "https://api.tienda.com/orders",
"params": [
{ "key": "locale", "value": "es-MX" }
],
"headers": [
{ "key": "Content-Type", "value": "application/json" }
],
"body": {
"mode": "json",
"raw": "{ \"customer\": \"{{customerId}}\", \"note\": \"{{note}}\" }"
},
"auth": { "type": "bearer", "token": "sk_live_xxx" },
"settings": { "timeoutMs": 30000 }
} | Campo | Tipo | Descripción |
|---|---|---|
method | string | GET, POST, PUT, PATCH o DELETE. |
url | string | URL destino. Admite {{variable}} en cualquier parte. |
params | array | Query params como { key, value, enabled? }. Máximo 25. |
headers | array | Igual que params. Máximo 25. |
body | objeto | { "mode": "none" }, { "mode": "json", "raw": "..." }, { "mode": "text", "raw": "..." } o { "mode": "form-urlencoded", "pairs": [...] }. |
auth | objeto | { "type": "none" }, { "type": "bearer", "token" }, { "type": "basic", "username", "password" } o { "type": "apikey", "key", "value", "in": "header" \| "query" }. |
settings.timeoutMs | number | Entre 1000 y 60000. Default 30000. |
Cualquier value admite {{variable}}, no sólo la URL.
{
"name": "orderId",
"type": "string",
"description": "Folio del pedido, tal como aparece en el correo de confirmación.",
"required": true,
"mode": "ai"
} | Campo | Tipo | Descripción |
|---|---|---|
name | string | Se referencia como {{name}} dentro de request. |
type | string | string, number, integer, boolean, array u object. |
description | string | Lo que lee el modelo. Obligatoria para variables en modo ai al habilitar. |
required | boolean | Si el modelo debe mandarla siempre. |
mode | string | ai (default), constant o context. |
constantValue | cualquiera | Sólo con mode: "constant". |
contextField | string | Sólo con mode: "context". Ver abajo. |
enum, format, pattern, minLength, maxLength, minimum, maximum, items, default | varios | Refinamientos que se copian al JSON Schema del modelo. |
Valores admitidos en contextField, disponibles cuando passContext es true:
contextField | Valor |
|---|---|
phoneNumber | Número del cliente en la conversación |
workspaceId | ID del workspace |
conversationId | ID de la conversación |
agentId | ID del agente que llama |
agentName | Nombre del agente que llama |
channelId | Canal por el que llegó la conversación |
lastMessages | Últimos N mensajes, según context.lastMessagesN |
Las respuestas grandes gastan contexto del modelo sin aportar nada. response permite quedarse sólo con lo útil:
| Campo | Tipo | Descripción |
|---|---|---|
path | string | Ruta al fragmento útil, ej. data.items. |
strictPath | boolean | Si true, falla cuando path no existe en lugar de devolver todo. |
include | string[] | Sólo estos campos. |
exclude | string[] | Todos menos estos. |
maxBytes | number | Corta la respuesta a este tamaño. Default 32000. |
Respuesta
{
"status": "success",
"message": "API tool created successfully",
"data": {
"id": "RuzoaswTBBrhutHyKYZn",
"name": "order_lookup",
"toolName": "api_order_lookup",
"status": "draft"
}
} Errores
| Status | Causa |
|---|---|
400 | El name no cumple el formato, la descripción es muy corta, o el request es inválido |
409 | Ya existe otra herramienta con ese nombre en el workspace |
Obtener API
GET https://api.platica.mx/v1/tools/apis/{integrationId} Parámetros de URL
| Parámetro | Tipo | Descripción | Requerido |
|---|---|---|---|
integrationId | string | Identificador de la API personalizada | ✓ |
Respuesta
Devuelve la definición y el toolName derivado. Los valores write-only se sustituyen por "[REDACTED]": autenticación, headers/params sensibles, variables constantes y la llave de encryptPayload.
{
"id": "RuzoaswTBBrhutHyKYZn",
"toolName": "api_order_lookup",
"name": "order_lookup",
"description": "Consulta el estado de un pedido de la tienda por su folio.",
"status": "enabled",
"request": {
"method": "GET",
"url": "https://api.tienda.com/orders/{{orderId}}",
"headers": [{ "key": "Accept", "value": "application/json" }],
"auth": { "type": "bearer", "token": "[REDACTED]" }
},
"variables": [
{
"name": "orderId",
"type": "string",
"description": "Folio del pedido, tal como aparece en el correo de confirmación.",
"required": true,
"mode": "ai"
}
],
"version": 3,
"enabledFunctionRef": "RuzoaswTBBrhutHyKYZn",
"secretsRedacted": true,
"createdAt": "2026-07-10T15:41:03.902Z",
"updatedAt": "2026-07-12T09:18:44.117Z"
} version sube con cada escritura y sirve para el control de concurrencia al actualizar.
Puedes reenviar "[REDACTED]" en un PATCH: Platica conserva el valor actual. Para reemplazar una credencial manda el valor nuevo; para conservarla también puedes omitir el campo.
Errores
| Status | Causa |
|---|---|
404 | La API personalizada no existe en el workspace |
Actualizar API
Actualización parcial: sólo se modifican los campos que mandes, el resto se conserva.
PATCH https://api.platica.mx/v1/tools/apis/{integrationId} Parámetros de URL
| Parámetro | Tipo | Descripción | Requerido |
|---|---|---|---|
integrationId | string | Identificador de la API personalizada | ✓ |
Cuerpo de la solicitud
{
"description": "Consulta el estado y la fecha estimada de entrega de un pedido.",
"expectedVersion": 3
} Acepta los mismos campos que crear , todos opcionales, más:
| Parámetro | Tipo | Descripción |
|---|---|---|
expectedVersion | number | Si la versión guardada no coincide, responde 409 en lugar de sobrescribir cambios de otro |
variables y los arrays de request (headers, params) se reemplazan completos, no se fusionan elemento por elemento. Para agregar una variable, manda el arreglo entero con la nueva incluida.
Si la herramienta está enabled, los cambios de nombre, descripción y variables se propagan al catálogo de inmediato. El status no cambia aquí — para eso están habilitar y pausar .
Respuesta
{
"status": "success",
"message": "API tool updated successfully",
"data": {
"id": "RuzoaswTBBrhutHyKYZn",
"version": 4
}
} Errores
| Status | Causa |
|---|---|
400 | Algún campo enviado es inválido, o el cuerpo viene vacío |
404 | La API personalizada no existe |
409 | expectedVersion no coincide, o el nombre nuevo ya está en uso |
Probar API
Ejecuta la herramienta con valores de prueba, en borrador o habilitada. Cada ejecución queda registrada en los logs de la integración.
POST https://api.platica.mx/v1/tools/apis/{integrationId}/test Parámetros de URL
| Parámetro | Tipo | Descripción | Requerido |
|---|---|---|---|
integrationId | string | Identificador de la API personalizada | ✓ |
Cuerpo de la solicitud
{
"dryRun": false,
"input": {
"orderId": "MX-48210"
},
"context": {
"phoneNumber": "+5215512345678"
}
} | Parámetro | Tipo | Descripción | Requerido | Default |
|---|---|---|---|---|
dryRun | boolean | Con true arma la petición y la devuelve sin llamar a la API | — | false |
input | objeto | Valores para las variables en modo ai | — | {} |
context | objeto | Valores de prueba para {{ctx.*}}: phoneNumber, workspaceId, conversationId, agentId, agentName, channelId, messages | — | — |
Empieza siempre con dryRun: true para verificar cómo quedan la URL, los headers y el body con las sustituciones aplicadas, antes de golpear la API real.
Respuesta
{
"status": "success",
"message": "Test executed",
"data": {
"outcome": "success",
"httpStatus": 200,
"durationMs": 412,
"request": {
"method": "GET",
"url": "https://api.tienda.com/orders/MX-48210"
},
"response": {
"status": "in_transit",
"eta": "2026-07-16"
}
}
} Errores
| Status | Causa |
|---|---|
404 | La API personalizada no existe |
Un fallo de la API remota no es un error de este endpoint: responde 200 con el detalle en data.outcome y data.httpStatus.
Habilitar API
Publica la herramienta en el catálogo del workspace.
POST https://api.platica.mx/v1/tools/apis/{integrationId}/enable Parámetros de URL
| Parámetro | Tipo | Descripción | Requerido |
|---|---|---|---|
integrationId | string | Identificador de la API personalizada | ✓ |
Respuesta
{
"status": "success",
"message": "API tool enabled successfully",
"data": {
"id": "RuzoaswTBBrhutHyKYZn",
"toolId": "RuzoaswTBBrhutHyKYZn",
"status": "enabled"
}
} toolId es lo que se pasa a POST /v1/agents/{agentId}/tools para dársela a un agente.
Volver a habilitar una herramienta ya habilitada re-sincroniza el catálogo, lo cual es útil después de editar el esquema.
Errores
| Status | Causa |
|---|---|
400 | Falta una descripción en alguna variable visible para el modelo, o la definición no pasa la validación |
404 | La API personalizada no existe |
409 | Ya existe otra herramienta con ese nombre en el workspace |
Pausar API
Retira la herramienta del catálogo. Los agentes dejan de verla de inmediato, pero la configuración se conserva íntegra.
POST https://api.platica.mx/v1/tools/apis/{integrationId}/pause Parámetros de URL
| Parámetro | Tipo | Descripción | Requerido |
|---|---|---|---|
integrationId | string | Identificador de la API personalizada | ✓ |
Respuesta
{
"status": "success",
"message": "API tool paused successfully",
"data": {
"id": "RuzoaswTBBrhutHyKYZn",
"status": "paused"
}
} Errores
| Status | Causa |
|---|---|
404 | La API personalizada no existe |
Eliminar API
DELETE https://api.platica.mx/v1/tools/apis/{integrationId} Parámetros de URL
| Parámetro | Tipo | Descripción | Requerido |
|---|---|---|---|
integrationId | string | Identificador de la API personalizada | ✓ |
Respuesta
{
"status": "success",
"message": "API tool deleted successfully",
"data": {
"id": "RuzoaswTBBrhutHyKYZn",
"removedAgentConnections": 3
}
} Elimina la configuración, su entrada del catálogo y todas sus conexiones con agentes. No es reversible — si sólo quieres apagarla conservando las asignaciones, usa pausar .
Errores
| Status | Causa |
|---|---|
404 | La API personalizada no existe |