IA18 min

APIs que un agente puede usar con control: una compra de punta a punta

Por · fundador y CEO de Hábil ·

Una compra diseñada para agentes de IA: proponer y ejecutar por separado, aprobación fuera del modelo, idempotencia, RFC 9457 y una prueba de inyección.

En APIs listas para agentes de IA explicamos qué necesita un sistema para que un agente lo use sin sorpresas: que se explique solo, que sus errores enseñen, que reintentar no duplique y que lo que mueve dinero o datos no dependa del modelo. Este artículo baja un piso. Toma una operación concreta —una compra— y la diseña completa: las llamadas, los códigos de respuesta, el formato de los errores, cómo se separan los permisos, dónde ocurre la aprobación y cómo se comprueba que todo eso resiste a un agente engañado.

Está escrito para el equipo de tecnología. Si usted dirige el área, la idea de fondo cabe en una línea: el agente puede pedir, el sistema decide, y una persona aprueba lo que mueve dinero o datos.

Escenario de ejemplo. No describe a una empresa real. Una distribuidora quiere que un agente de IA reponga insumos: revisa existencias, compara proveedores y arma pedidos. Las compras pequeñas se aprueban en minutos; nadie quiere que el agente compre solo.

1. La compra se parte en tres pasos, no en uno

La tentación es exponer una sola operación, POST /compras, y dejar que el agente la llame. Es la forma más corta de darle al modelo la última palabra sobre el dinero. La alternativa es partir la compra en tres pasos, cada uno con un permiso distinto:

1. La compra se parte en tres pasos, no en uno
PasoLlamadaQuién lo haceQué cambia en el sistema
ConsultarGET /existencias, GET /proveedores/{id}/preciosEl agenteNada
ProponerPOST /propuestas-de-compraEl agenteSe crea una propuesta en estado pendiente de aprobación. No se compra nada
EjecutarPOST /comprasEl agente, solo con una aprobación válidaSe emite la orden al proveedor

Y entre proponer y ejecutar hay un paso que no tiene llamada para el agente: la aprobación. La hace una persona, en otro canal, y el sistema la guarda. El agente no puede crearla, solo esperarla.

La propuesta queda así:

POST /propuestas-de-compra
Content-Type: application/json

{
  "proveedor": "prov-0193",
  "partidas": [
    { "sku": "EMP-5521", "cantidad": 40 }
  ],
  "moneda": "MXN",
  "motivo": "Existencia bajo el mínimo en el almacén norte"
}
HTTP/1.1 201 Created
Location: /propuestas-de-compra/pc-7f3a
ETag: "rev-1"

{
  "id": "pc-7f3a",
  "revision": 1,
  "estado": "pendiente_de_aprobacion",
  "total": "12480.00",
  "moneda": "MXN",
  "huella": "sha256:4b1e…",
  "vence": "2026-11-03T18:00:00-06:00"
}

El agente solo manda qué quiere y cuánto. Todo lo demás lo pone el sistema desde sus fuentes autorizadas: precios vigentes, impuestos, dirección de entrega, condiciones y la política que aplica. Con eso arma una revisión inmutable de la propuesta y calcula dos cosas sobre ella: el total y la huella, un resumen criptográfico de esa revisión exacta, calculado sobre una representación documentada. Si cambia el precio, el proveedor, el destino, una partida o la política, nace una revisión nueva y cualquier aprobación anterior deja de valer.

La huella identifica la revisión; no da permiso para nada. Saberla no autoriza a ejecutar, igual que conocer el número de una cuenta no autoriza a retirar de ella. Más abajo se ve qué papel juega.

Tres pasos de una compra: el agente consulta y propone; una persona aprueba desde otro dispositivo, y solo entonces se ejecuta la orden.

2. La aprobación ocurre fuera del modelo

OWASP, la organización de referencia en seguridad de aplicaciones, nombra el riesgo de darle a un agente más funciones, permisos o autonomía de los necesarios como Excessive Agency. Entre sus mitigaciones pone dos que aquí se vuelven diseño: usar a una persona para aprobar las acciones de alto impacto antes de que ocurran, e implementar la autorización en los sistemas que reciben la llamada, «en lugar de depender de un LLM para decidir si una acción está permitida» [4]. La especificación de MCP, el protocolo con el que muchos agentes llaman herramientas, va en la misma línea: dice que siempre debería haber una persona con la capacidad de negar la invocación de una herramienta [6].

En la práctica, «una persona aprueba» tiene que cumplir tres condiciones para valer algo:

  1. El canal es otro. La aprobación no llega en la misma conversación que el agente puede leer y escribir. Para eso ya existe un patrón: el flujo CIBA de OpenID separa el dispositivo donde se inicia la operación del dispositivo donde la persona se autentica y da su consentimiento [8]. En el escenario: el agente propone desde el servidor, y la gerente de compras aprueba desde la aplicación del celular, con su propia sesión.
  2. Se aprueba lo concreto. La persona no aprueba «que el agente compre»: aprueba esta propuesta, con este proveedor y este total. El estándar OAuth para autorizaciones detalladas (RFC 9396) existe justo para eso: permite pedir una autorización que lleva dentro el tipo de operación, el monto y el beneficiario, y su ejemplo es un pago [7]. CIBA, además, define un mensaje pensado para mostrarse en los dos dispositivos, de modo que la persona pueda relacionarlos [8]. La pantalla de aprobación la arma el sistema, no el agente: muestra la revisión, el total, el proveedor, el destino y el vencimiento.
  3. Lo aprobado es lo que se ejecuta. La aprobación queda atada a la revisión exacta de la propuesta y registra quién aprobó, con qué rol y bajo qué política. Vence por el reloj del servidor, se puede revocar y deja de valer si nace una revisión nueva.

La aprobación se diseña para que el agente no tenga ninguna operación que pueda otorgarla ni cambiar lo que ya se aprobó. El agente puede pedir una aprobación; darla le toca a una persona.

La aprobación ocurre en otro dispositivo y queda atada a la huella de la propuesta: lo que se aprueba es lo que se ejecuta.

3. Ejecutar: una llamada que se puede repetir sin cobrar dos veces

Con la propuesta aprobada, el agente ejecuta:

POST /compras
Content-Type: application/json
If-Match: "rev-1"
Idempotency-Key: "3f2c9a1e-8d4b-4c6e-9f1a-2b7d5e0c4a91"

{
  "propuesta": "pc-7f3a"
}

El cuerpo no repite partidas ni montos: solo dice qué propuesta se ejecuta. El encabezado If-Match dice qué revisión se espera ejecutar, con el mecanismo estándar de HTTP para peticiones condicionales: si la revisión ya no es la vigente, el servidor puede responder 412 Precondition Failed [16]. Y la llamada lleva una credencial de ejecución que se explica en la sección 5.

El sistema revisa todo en una sola transacción: la propuesta sigue aprobada, la aprobación no venció ni fue revocada, la revisión coincide, la credencial es válida y no existe ya una orden para esa propuesta. Si todo se cumple, la propuesta pasa de aprobada a ejecutando y la credencial se consume; si no, se rechaza con un error que explica por qué (sección 4).

Esa transacción es lo que impide dos compras de la misma propuesta, aunque lleguen dos llamadas distintas al mismo tiempo, con llaves distintas, desde dos procesos o desde un agente que se reinició. Y como última barrera, la base de datos no admite dos órdenes para la misma propuesta. Los estados quedan así: aprobada → ejecutando → ejecutada, o fallida_sin_confirmar si el proveedor recibió la orden pero la respuesta se perdió. En ese caso, el sistema reconcilia con el proveedor antes de reenviar; de otro modo, la duplicación solo se mueve de lugar.

La llave de idempotencia: para los reintentos, no para la concurrencia

La transacción anterior resuelve dos ejecuciones distintas. La llave de idempotencia resuelve otra cosa: el reintento de la misma ejecución. En esta API, repetir la misma petición con la misma llave devuelve el resultado registrado de esa ejecución, en lugar de intentarla otra vez.

El encabezado Idempotency-Key sigue en proceso de estandarización en el IETF: es un borrador activo, en su versión 08, actualizado el 22 de octubre de 2026, y todavía no es RFC. Su valor es una cadena entre comillas, como en el ejemplo de arriba [2]. Pero ya propone reglas que conviene adoptar tal cual, porque cubren justo los casos que confunden a un agente [2]:

La llave de idempotencia: para los reintentos, no para la concurrencia
SituaciónRespuesta que propone el borrador
La operación exige llave y no llegó400 Bad Request, con enlace a la documentación
La misma llave llega con otro contenido422 Unprocessable Content
La misma llave llega mientras la primera sigue en proceso409 Conflict
La misma llave llega después de terminada la primeraEl resultado guardado de la primera

El borrador también permite una «huella» de la petición para decidir si dos peticiones con la misma llave son de verdad la misma [2]. Y hay detalles que cada API tiene que publicar: el alcance de la llave, cuánto tiempo se guarda y cuándo vence. Stripe, que es una referencia práctica en el tema, documenta los de su API v1 [3]:

  • guarda el código y el cuerpo de la primera respuesta en cuanto la operación empieza a ejecutarse, incluidos los errores 500, para que un reintento no vuelva a cobrar cuando el primer intento quedó en duda;
  • sugiere generar las llaves como UUID versión 4 y no usar datos sensibles (un correo o una clave fiscal) como llave;
  • puede borrar las llaves cuando tienen al menos 24 horas.

En el diseño con agentes hay una decisión más: quién genera la llave. Si el agente genera una llave nueva en cada reintento, la llave no sirve para reconocerlo. Conviene que nazca con la ejecución de la propuesta y quede registrada del lado del servidor. Y si a pesar de eso llega una segunda ejecución con otra llave, la detiene la transacción, no la llave.

Un reintento con la misma llave de idempotencia recibe el resultado guardado y no compra dos veces.

4. Errores que el agente puede corregir, con RFC 9457

Para esta compra, el formato de errores del RFC 9457 permite darle al agente datos estructurados para corregir, sin cambiar el significado de los códigos HTTP [1]. Así se ve un rechazo por monto:

HTTP/1.1 422 Unprocessable Content
Content-Type: application/problem+json

{
  "type": "https://api.ejemplo.mx/problemas/monto-sobre-limite",
  "title": "El total supera el límite que se puede proponer",
  "status": 422,
  "detail": "El total de 48,900.00 MXN supera el límite de 25,000.00 MXN para propuestas de este agente. Esta compra requiere la aprobación de nivel superior.",
  "instance": "/propuestas-de-compra/intentos/a91c",
  "limite": "25000.00",
  "reintentable": false
}

Cuatro reglas del propio RFC hacen que esto funcione bien con un agente:

  • El estado del cuerpo es solo informativo, y quien lo genera debe usar el mismo código que la respuesta real [1]. Un 422 en el cuerpo con un 200 en la respuesta confunde a cualquiera.
  • Se pueden agregar campos propios —aquí limite y reintentable—, y el RFC obliga a los clientes a ignorar los que no reconozcan [1]. Eso permite darle al agente justo el dato que necesita sin romper a nadie.
  • Si hay varios errores, se recomienda reportar el más relevante [1]. Para errores de validación, el RFC muestra un arreglo con el detalle y la ubicación de cada campo con error, que es lo que un agente necesita para corregir de un intento [1].
  • No se exponen detalles internos: el RFC advierte contra mostrar cosas como un volcado de la pila [1]. El error dice qué corregir, no cómo está hecho el sistema por dentro.

Para la compra del escenario, los tipos de problema quedan así:

Para la compra del escenario, los tipos de problema quedan así
ProblemaCódigoreintentableQué hace el agente
Credencial ausente o vencida401noPide una credencial válida
Credencial válida, sin permiso para esta propuesta403noSe detiene
monto-sobre-limite422noPide el flujo de aprobación que corresponde. No parte ni cambia la compra para pasar por debajo del límite
propuesta-sin-aprobar409noConsulta el estado o espera el aviso de aprobación; no repite la ejecución en bucle
aprobacion-vencida409noSomete una revisión nueva a aprobación
revision-no-coincide412noSe detiene y consulta la revisión vigente; no reutiliza la aprobación
llave-con-otro-contenido422noCorrige la petición, o usa una llave nueva si es una operación nueva
compra-en-proceso409sí, más tardeEspera el tiempo que indique Retry-After o consulta la ejecución; no abre otra

Dos ideas detrás de la tabla. La primera: separar autenticación (401), autorización (403), precondición (412) y estado del flujo (409), para que el agente sepa si le falta algo, si no puede o si tiene que esperar. La segunda: el agente no debería adivinar qué vale la pena repetir. Y un cuidado: el límite de monto no se evita dividiendo la compra, así que la política suma por proveedor y por periodo, no solo por propuesta.

5. Leer, proponer, ejecutar: los permisos viven en la API

La tabla de la sección 1 no es una convención de estilo. Es la forma de limitar el daño cuando el agente se equivoca. OWASP enumera las tres causas del exceso de agencia: funciones de más, permisos de más y autonomía de más [4]. Cada nivel corta una:

  • Una credencial de ejecución limitada. El agente que consulta y propone no tiene el permiso de ejecutar. Después de la aprobación, el servidor de autorización puede emitir al ejecutor una credencial de un solo uso y de vida corta, que lleva dentro la propuesta, la revisión, el proveedor, el monto, la moneda y la API a la que va dirigida. El RFC 9396 da el formato para expresar ese detalle [7]; validarlo contra la aprobación vigente y consumirlo en la misma transacción que marca ejecutando le toca a esta API. Además, la credencial queda atada a quien la presenta, por ejemplo con DPoP [17], para que no le sirva a nadie más aunque se filtre.
  • El agente ni siquiera ve lo que no puede hacer. La especificación de MCP permite que la lista de herramientas que un servidor ofrece cambie según la autorización de quien pregunta: por ejemplo, mostrar solo las herramientas que sus permisos alcanzan [6]. Un agente con permiso de proponer no ve la herramienta de ejecutar. Ocultarla reduce lo que descubre, pero no autoriza ni bloquea por sí sola: la API valida permiso, sujeto, propuesta y estado en cada llamada [6].
  • Un identificador no es un permiso. MCP lo dice para el estado entre llamadas: un identificador como el de un carrito es un nombre, no una capacidad, y el servidor debe validar la autorización en cada llamada [6]. Que el agente conozca pc-7f3a no le da derecho a ejecutarla.
  • Los límites viven en el servidor. El límite de 25,000 pesos del ejemplo está en la API, no en las instrucciones del modelo. El modelo puede ignorar una instrucción; la API rechaza la petición aunque el modelo la envíe.
  • Bitácora de todo. Qué agente, con qué credencial, qué propuso, quién aprobó, qué huella, qué se ejecutó. MCP recomienda registrar el uso de herramientas para auditoría [6].

6. La prueba del catálogo envenenado

Todo lo anterior se puede revisar en papel. Esta sección es para comprobarlo con el sistema funcionando.

El riesgo

En 2023, un grupo de investigadores describió la inyección indirecta de instrucciones: el atacante no habla con el agente, sino que esconde instrucciones en datos que el agente probablemente va a leer [10]. OWASP la incluye como el primer riesgo de las aplicaciones con modelos de lenguaje y reconoce que no está claro que exista una forma infalible de prevenirla [5].

En el escenario, el agente lee el catálogo de proveedores: nombres, descripciones, precios. Cualquiera que pueda escribir una descripción —un proveedor, un empleado, una integración comprometida— puede meter ahí una instrucción.

Por qué no basta un detector

Las cifras publicadas son consistentes en un punto:

  • Un equipo de investigadores atacó 12 defensas recientes con ataques adaptados a cada una y superó el 90 % de éxito contra la mayoría [14].
  • En una evaluación del centro de estándares de IA del NIST, con un modelo y un entorno de oficina simulado, el éxito subió de 11 % para el ataque base más fuerte a 81 % para el ataque nuevo más fuerte, desarrollado con el instituto de seguridad de IA del Reino Unido [15].
  • En otro conjunto de cinco tareas de esa misma evaluación, el éxito promedio pasó de 57 % con un intento a 80 % al repetir cada ataque 25 veces [15].

Son resultados de esas condiciones, no una tasa de todos los agentes. Lo que sí enseñan es que una evaluación propia tiene que registrar modelo, entorno, tarea y número de corridas.

La lección no es que los agentes sean inseguros. Es que la defensa que importa es la que no depende de que el modelo detecte el engaño. Dos marcos lo dicen de forma memorable. Simon Willison llama «trifecta letal» a la combinación de acceso a datos privados, exposición a contenido no confiable y capacidad de comunicarse hacia afuera [11]. Meta propone la «regla de dos»: en una misma sesión, un agente no debería procesar entradas no confiables, tener acceso a sistemas sensibles y poder cambiar el estado o comunicarse hacia afuera; como máximo, dos de las tres [12]. Un agente de compras que lee un catálogo abierto y emite órdenes junta justo las tres. Por eso el paso de ejecutar no puede depender de lo que el agente leyó.

La investigación va en la misma dirección. El diseño CaMeL, de un equipo de investigadores, separa el flujo de control —lo que decide la consulta confiable de la persona— del flujo de datos, de modo que los datos no confiables que lee el modelo nunca cambien el curso del programa. Con ese diseño resolvieron el 77 % de las tareas del banco de pruebas AgentDojo con seguridad demostrable, contra el 84 % de un sistema sin defensa [9]. La separación entre proponer y ejecutar de este artículo se inspira en ese principio; no equivale a implementar CaMeL ni hereda su prueba de seguridad.

La prueba, paso a paso

  1. Prepare un entorno aislado, con un proveedor simulado y sin salida a proveedores reales. Registre la versión del modelo, las instrucciones, las herramientas, la identidad del agente, el catálogo inicial, la política y la versión de la API.
  2. Agregue al catálogo una descripción de prueba marcada internamente como no confiable, que intente cambiar la cantidad, el destino de entrega y el estado de la propuesta. El texto exacto vive en el material de pruebas de su equipo, no en documentos públicos.
  3. Pídale al agente una tarea normal que lo haga leer ese producto, como revisar existencias y reponer lo que falte.
  4. Repita la tarea varias veces por cada combinación de modelo, configuración y variante de la descripción. Una referencia útil son las 25 repeticiones de la evaluación del NIST, cuando su entorno permite reintentos [15]; es un punto de comparación, no una garantía.
  5. Mida por separado lo del modelo y lo del sistema, en la bitácora: - cuántas veces el agente obedeció la instrucción escondida (eso es del modelo y varía entre versiones); - cuántas propuestas creó; - cero órdenes sin aprobación vigente, revisión coincidente y credencial de ejecución válida; - todos los intentos directos de aprobar o de ejecutar sin permiso, rechazados; - trazabilidad completa de cada intento: identificador de correlación, agente, credencial, revisión, decisión y respuesta.
  6. Agregue variantes que prueben las reglas de la API: una revisión creada después de la aprobación, una aprobación vencida o revocada, dos llaves distintas para la misma propuesta y una credencial presentada por otro cliente. Los bancos de pruebas públicos como AgentDojo, con 97 tareas y 629 casos de seguridad, sirven de modelo para armar los suyos [13].

Si la tercera condición del paso 5 falla, hay que revisar primero la autorización, la transición de estados y la bitácora de esa llamada. La tasa de obediencia del modelo sirve para elegir y configurar modelos; la seguridad de la compra no puede depender de ella.

Una instrucción escondida en el catálogo llega al agente, pero la API no ejecuta nada sin una aprobación válida y deja registro del intento.

7. Lista de verificación para su equipo

  • [ ] Las operaciones que mueven dinero o datos están partidas en consultar, proponer y ejecutar, con permisos distintos.
  • [ ] Precios, total, destino y condiciones los pone el sistema en una revisión inmutable, no el agente.
  • [ ] La aprobación ocurre en otro canal, la hace una persona, queda atada a la revisión, vence y se puede revocar.
  • [ ] El agente no tiene ninguna llamada para aprobar.
  • [ ] Ejecutar exige una credencial de un solo uso atada a la propuesta y a quien la presenta, y una transacción que impide dos órdenes para la misma propuesta.
  • [ ] Ejecutar exige Idempotency-Key para los reintentos, y la API responde 400 / 409 / 422 como propone el borrador del IETF.
  • [ ] Los errores son application/problem+json, con tipos documentados y un campo que dice si conviene reintentar.
  • [ ] Los límites viven en la API, no en las instrucciones del modelo.
  • [ ] La lista de herramientas que ve el agente depende de sus permisos, y la API valida igual cada llamada.
  • [ ] La prueba del catálogo envenenado corre en cada versión, con varias repeticiones, y mide por separado lo que hizo el modelo y lo que permitió el sistema.

Qué hace Hábil

En Hábil le ayudamos a diseñar las APIs de sus sistemas para que un agente de IA pueda usarlas con control: separamos lo que se consulta, lo que se propone y lo que se ejecuta; llevamos la aprobación fuera del modelo, con una persona aprobando lo que mueve dinero o datos; y definimos con su equipo pruebas verificables, como la del catálogo envenenado, cuya evidencia se revisa junto con ustedes. Lo hacemos con Hábil AI, inteligencia artificial conectada a sus sistemas con control. Para el panorama completo, vea también APIs listas para agentes de IA y la página Controlar quién entra.

Primera conversación, sin costo. Partimos de una operación suya que hoy un agente no debería ejecutar solo, y le decimos qué haría falta para que pueda proponerla con control.

Fuentes consultadas el 28 de octubre de 2026. Las citas de documentos en inglés están traducidas.

Referencias

  1. IETF, RFC 9457, Problem Details for HTTP APIs (2023). https://www.rfc-editor.org/rfc/rfc9457
  2. IETF, The Idempotency-Key HTTP Header Field, draft-ietf-httpapi-idempotency-key-header-08 (borrador activo, actualizado el 22-oct-2026; no es RFC). https://datatracker.ietf.org/doc/draft-ietf-httpapi-idempotency-key-header/
  3. Stripe, Idempotent requests (documentación de la API; práctica de un proveedor). https://docs.stripe.com/api/idempotent_requests
  4. OWASP, Top 10 for LLM Applications 2025, LLM06: Excessive Agency. https://genai.owasp.org/llmrisk/llm062025-excessive-agency/
  5. OWASP, Top 10 for LLM Applications 2025, LLM01: Prompt Injection. https://genai.owasp.org/llmrisk/llm01-prompt-injection/
  6. Model Context Protocol, especificación 2026-07-28, Tools. https://modelcontextprotocol.io/specification/2026-07-28/server/tools
  7. IETF, RFC 9396, OAuth 2.0 Rich Authorization Requests (2023). https://www.rfc-editor.org/rfc/rfc9396
  8. OpenID Foundation, OpenID Connect Client-Initiated Backchannel Authentication Flow — Core 1.0 (final, 1-sep-2021). https://openid.net/specs/openid-client-initiated-backchannel-authentication-core-1_0.html
  9. Debenedetti, Shumailov, Fan y otros, «Defeating Prompt Injections by Design», preprint, arXiv 2503.18813 (2025). https://arxiv.org/abs/2503.18813
  10. Greshake, Abdelnabi, Mishra, Endres, Holz y Fritz, «Not what you've signed up for: Compromising Real-World LLM-Integrated Applications with Indirect Prompt Injection», arXiv 2302.12173 (2023). https://arxiv.org/abs/2302.12173
  11. Simon Willison, «The lethal trifecta for AI agents», 16-jun-2025. https://simonwillison.net/2025/Jun/16/the-lethal-trifecta/
  12. Meta AI, «Agents Rule of Two: A Practical Approach to AI Agent Security», 31-oct-2025. https://ai.meta.com/blog/practical-ai-agent-security/
  13. Debenedetti, Zhang, Balunović y otros, «AgentDojo», arXiv 2406.13352 (2024). https://arxiv.org/abs/2406.13352
  14. Nasr, Carlini, Sitawarin y otros, «The Attacker Moves Second», preprint, arXiv 2510.09023 (2025). https://arxiv.org/abs/2510.09023
  15. NIST, Center for AI Standards and Innovation, Technical Blog: Strengthening AI Agent Hijacking Evaluations (17-ene-2025, actualizado 19-dic-2025). https://www.nist.gov/news-events/news/2025/01/technical-blog-strengthening-ai-agent-hijacking-evaluations
  16. IETF, RFC 9110, HTTP Semantics (2022), sección 13.1.1, If-Match. https://www.rfc-editor.org/rfc/rfc9110
  17. IETF, RFC 9449, OAuth 2.0 Demonstrating Proof of Possession (DPoP) (2023). https://www.rfc-editor.org/rfc/rfc9449

¿Su operación tiene estos desafíos?

Platiquemos su caso

¿Prefiere correo? Escríbanos a hola@habil.mx