← Blog
14 de octubre, 2026 · 16 min

Pagar por un no: cobro de refusals, fallback credit y x402

Un agente puede pagar por una respuesta y recibir un refusal. Que ese refusal cueste algo depende del proveedor, de la categoría de política, del momento en que llegó y de un solo chequeo de status code en el middleware de pago del vendedor.

Los refusals eran un caso borde. En 2026 son una superficie de la API. Los modelos más nuevos de Anthropic corren clasificadores de seguridad que rechazan requests con una categoría con nombre. GPT-6 de OpenAI devuelve un código de error de política en lugar de output. Y cualquier modelo todavía puede escribir "I can't help with that" como texto plano.

En una cuenta prepaga, un refusal es una línea más en la factura de fin de mes. Para un agente que paga por llamada vía x402, es un pago que ya firmó. Así que hicimos una pregunta acotada: cuando la respuesta es no, ¿quién paga, cuánto, y alguien aguas abajo puede notarlo?

Nuestras fuentes, todas leídas o ejecutadas el 2026-10-14: las páginas de refusals y fallback, fallback credit, streaming refusals y pricing de Anthropic, más sus release notes de la API; las guías de structured outputs y de clasificadores de seguridad de OpenAI y su spec OpenAPI en 8035270; el FAQ de billing, la guía de safety settings y la referencia de generateContent de Gemini; la documentación de errores y de model fallbacks de OpenRouter; LiteLLM en b22a0bd; el Vercel AI SDK en 6ac1ee1; browser-use en c75e847; y los middlewares de referencia de x402 en dd927a2. También corrimos 480 llamadas contra dos modelos locales en Ollama 0.30.6.

La versión corta: solo un proveedor documenta cómo cobra un refusal, y esa regla cambió dos veces en cuatro meses. El campo que decide la factura se pierde en cuanto la respuesta se traduce al formato Chat Completions. Y el middleware de referencia de x402 settlea según el status HTTP, así que un refusal que llega como 200 es una venta salvo que el vendedor decida otra cosa.

Tres tipos de no

El modelo lo escribe. Es el tipo más antiguo y sigue siendo el más común. El refusal es output normal. La guía de structured outputs de OpenAI agrega un campo refusal separado para refusals de seguridad, porque un refusal "does not necessarily follow the schema you have supplied". La propia taxonomía de Anthropic clasifica los "model-generated refusals" como "standard text responses".

Un clasificador rechaza y la API devuelve un 200. La página de refusals y fallback de Anthropic dice que Claude Fable 5.1, Fable 5, Opus 5.5, Opus 5, Sonnet 5.5 y Haiku 5.5 "include safety classifiers that can decline a request". La respuesta es "a normal response, not an error", con stop_reason: "refusal" y un objeto stop_details. Su category es una de cyber, bio, frontier_llm, reasoning_extraction o general_harms, o null cuando no aplica ninguna categoría con nombre. El rechazo puede llegar antes de cualquier output o a mitad de stream. En un Message Batch, un item rechazado vuelve como result.type: "succeeded".

Un clasificador rechaza y la API devuelve un error. El enum de errores de Responses en la spec OpenAPI de OpenAI ahora incluye bio_policy. Un pull request de Codex mergeado el 7 de julio (openai/codex#31439) lo describe como un cambio de contrato de la Responses API "from invalid_prompt and the legacy message to bio_policy". Otro posterior (#46306, 17 de septiembre) hace que Codex lo trate como no reintentable, "recognizing streaming failures and HTTP 400 responses". cyber_policy aparece en los códigos de error de sesión de la spec. La guía de GPT-6 de OpenRouter documenta ambos códigos y los expone como un HTTP 403 con error_type: "refusal". Cuando el bloqueo llega con el stream ya iniciado, el 403 es un código dentro del body del error, "because the HTTP line was already committed".

Las herramientas no se ponen de acuerdo sobre qué tipo es este tercer caso. El framework Inspect del UK AISI hacía fallar muestras de evaluación con bio_policy hasta que un fix mergeado el 30 de septiembre lo convirtió en un output del modelo con stop_reason="content_filter". Codex lo mantiene como error. Mismo evento, dos contratos.

Gemini queda en el medio. Un prompt bloqueado devuelve promptFeedback.blockReason (SAFETY, OTHER, BLOCKLIST, PROHIBITED_CONTENT o IMAGE_SAFETY), y la referencia dice "no candidates are returned". Una respuesta bloqueada termina con finishReason: SAFETY, y "the content that was blocked is not returned". Ambos llegan como un GenerateContentResponse normal, no como un error HTTP.

Quién cobra qué

Anthropic es el único proveedor que encontramos que deja por escrito, en detalle, cómo cobra los refusals. La regla actual, de la misma página:

La regla aplica en la Claude API, Bedrock, Claude Platform on AWS, Google Cloud y Microsoft Foundry. Su historia es corta. Las release notes de la API muestran que el 2 de junio de 2026 Anthropic dejó de cobrar los refusals que llegan antes de cualquier output en la Claude API. El 24 de septiembre volvió a cobrarlos en las tres categorías de arriba, "the categories where we measure low volumes of false positives". La página de refusals agrega el motivo: "To disrupt attempts to circumvent Anthropic's safeguards at scale". También dice que la lista de categorías cobradas "may change".

Fíjate en lo que esto le hace al objeto usage. Un refusal gratis y un refusal cobrado reportan el mismo tipo de conteo de tokens. El usage por sí solo no te dice si te cobraron. Necesitas la categoría y el momento.

OpenAI no documenta una regla de cobro especial para los refusals que escribe el modelo; el refusal simplemente llega como output. Para los bloqueos bio_policy, no encontramos ninguna afirmación sobre el cobro, ni en un sentido ni en otro. El FAQ de billing de Gemini dice "If your request fails with a 400 or 500 error, you won't be charged for the tokens used. However, the request will still count against your quota." Un bloqueo de seguridad no es un 400, y las páginas que leímos no dicen cómo se cobra.

Una de las categorías cobradas merece una mirada más cercana de quien construye agentes. Anthropic dice que un refusal reasoning_extraction "usually comes from a prompt that asks the model to put its thinking or reasoning in the output". Su lista de disparadores comunes incluye "A reasoning, thinking, or trace field in JSON output or in a tool input". Es un patrón común en agentes. browser-use, por ejemplo, usa use_thinking=True por default, y entonces su schema AgentOutput incluye un campo thinking junto a cada acción. No probamos si ese schema provoca refusals en Claude. El punto es que una categoría que se cobra antes de cualquier output se superpone con una forma que los frameworks de agentes emiten a propósito.

El otro libro contable: la cuenta

Los refusals también se acumulan en otro lugar que no es la factura. La guía de clasificadores de seguridad de OpenAI describe una escalera de sanciones. Los requests se clasifican en umbrales de riesgo. "If your org hits high thresholds repeatedly, OpenAI returns an error and sends a warning email." Si los requests siguen más allá del plazo indicado, "usually seven days", OpenAI corta el acceso de la org a GPT-5, el modelo que cubre la guía.

La mitigación documentada es el parámetro safety_identifier: un ID estable y hasheado por usuario final, para que la sanción bloquee un identificador en lugar de toda la org. Un identificador bloqueado recibe un error "identifier blocked" en todos los requests futuros a GPT-5. La Messages API de Anthropic tiene un campo similar, metadata.user_id, que "Anthropic may use … to help detect abuse".

Para un vendedor multi-tenant, este libro contable es el riesgo mayor. La org es el vendedor. Sin un identificador por cliente, la escalera del proveedor ve un solo cliente, y los refusals de un agente cuentan contra todos los que pasan por la misma cuenta.

Lo que cuesta un fallback

La respuesta habitual a un refusal es reintentar en otro modelo. Anthropic ahora lo hace del lado del servidor. Poner fallbacks: "default" con el beta header server-side-fallback-2026-07-01 reintenta un request rechazado en el modelo que Anthropic recomienda para esa categoría de refusal. También puedes nombrar hasta tres modelos de fallback. Algunas reglas importan para el costo:

El costo oculto de cualquier fallback es el prompt cache. Los cachés son por modelo, así que el reintento tiene que escribir todo el prefijo de nuevo. El fallback credit resuelve eso: el refusal trae un fallback_credit_token, y un reintento que lo devuelve "is billed as though the conversation had been on the new model all along".

La diferencia es fácil de calcular. Toma una conversación cacheada de 40,000 tokens en Opus 5.5 que recibe un rechazo y pasa a Opus 4.8. Sin el credit, el reintento escribe 40,000 tokens en el caché de cinco minutos de Opus 4.8 a $6.25 por millón: $0.25. Con él, los mismos tokens se cobran como lecturas de caché a $0.50 por millón: $0.02. Si el intento rechazado no estaba cacheado y era de una categoría cobrada, además costó 40,000 × $4 por millón en Opus 5.5: $0.16, antes de cualquier output.

El credit tiene condiciones estrictas. El token "expires five minutes after the refusal". Se "redeems only from the organization and workspace that received the refusal". El reintento debe coincidir exactamente con el request rechazado en system, messages, tools, tool_choice, thinking y cache_control. El destino tiene que ser un fallback permitido: Opus 4.8 u Opus 5 para Fable 5.1, Fable 5 y Opus 5.5; Opus 4.8 para Opus 5; Sonnet 5 para Sonnet 5.5. Los refusals en batch no generan credit, y los refusals de Haiku 5.5 no traen ninguno.

En la práctica, el credit le pertenece a quien tiene el workspace. Un agente detrás de un gateway no puede canjearlo. Solo el gateway puede.

Los routers lo manejan distinto. Los model fallbacks de OpenRouter se disparan ante errores, incluidos los "Moderation flags for filtered models", y los requests se "priced using the model that was ultimately used". Aclara que su parámetro fallbacks en el endpoint de Messages "does not use Anthropic's server-side fallback feature". No reenvía un bloqueo de política 403 a otro endpoint que sirva el mismo modelo. El router de LiteLLM tiene content_policy_fallbacks. Un 200 cuyo finish_reason es content_filter se convierte en un ContentPolicyViolationError solo si hay un fallback de ese tipo configurado. Si no, "original response is returned". El chequeo corre sobre objetos ModelResponse no streaming.

Lo que sobrevive a la traducción

La mayoría de los agentes no habla la Messages API. Habla Chat Completions, a través de un SDK, un router o un gateway. La spec de OpenAI permite cinco valores de finish_reason: stop, length, tool_calls, content_filter y function_call. No hay valor refusal ni lugar para una categoría. Esto es lo que hace cada capa que leímos con un refusal de Anthropic:

Así que, cuando un refusal cruza al formato Chat Completions, el campo que decide si se cobró desaparece. Un cliente ve content_filter para un rechazo cyber gratis, un rechazo bio cobrado, un bloqueo de Gemini y, en el caso de LiteLLM, un OTHER sin explicación.

El refusal que nadie etiqueta

Los casos de clasificador al menos traen una marca. El refusal más común que encuentra un agente no trae ninguna: un modelo que sigue un system prompt que limita lo que puede responder. Todo vendedor con un system prompt los produce. Medimos cómo se ven en el cable.

Setup: Ollama 0.30.6, qwen2.5:7b y qwen2.5:3b, num_ctx 8192, temperatura 0.8, seeds 1000–1009, max_tokens 300, en el endpoint compatible con OpenAI. El system prompt convierte al modelo en un asistente de facturación que debe responder cualquier otra cosa con exactamente "I can't help with that." Enviamos cinco requests fuera de tema y un control dentro de tema, diez veces cada uno, en cuatro condiciones: contexto corto o largo (solo la política, unos 63 tokens, o la política más unos 2,600 tokens de texto de referencia) y texto libre o un response format json_schema estricto.

# requests fuera de tema rechazados, sobre 50 por celda
                     short/text  short/json  long/text  long/json
qwen2.5:7b               50          48          38         19
qwen2.5:3b               29          10          10          0

# las 480 llamadas
refusals                       204
finish_reason en refusals      "stop" 204/204
campo message.refusal presente 0/480
prompt tokens prom., refusal largo ~2,648  (7b: ~14 completion tokens)

Tres cosas resaltan. Primero, un refusal en el cable es indistinguible de una respuesta. Todos terminaron con finish_reason: "stop", ninguno llenó un campo refusal y todos reportaron usage completo. Solo leer el texto los diferencia.

Segundo, un refusal es casi todo input. Con el contexto largo, el modelo 7B gastó unos 2,648 prompt tokens para producir un refusal de unos 14 tokens. Lo que sea que el vendedor cobre por input, el agente lo paga por un no.

Tercero, el cumplimiento no es estable. Más contexto y un schema hicieron que la política se filtrara: el modelo 7B rechazó 50 de 50 requests fuera de tema con prompt corto y texto libre, y 19 de 50 con prompt largo y schema. Bajo el schema, los refusals que sí ocurrieron volvieron como objetos válidos, {"answer": "I can't help with that.", "invoice_items": []}, que cualquier validador acepta. Mostramos el mismo efecto del constrained decoding en nuestra auditoría de structured outputs; aquí aplica al refusal mismo.

x402 settlea según el status, no según el resultado

La especificación x402 v2 define cómo se verifica y se settlea un pago. No dice cuándo debe settlear un vendedor. Esa decisión vive en el middleware de referencia, y los cuatro que leímos la toman igual. Hono chequea res.status >= 400 y se salta el settlement; Express chequea res.statusCode >= 400; FastAPI chequea response.status_code >= 400; el middleware echo de Go chequea capture.statusCode >= 400.

Así que la forma del refusal decide el pago. Un refusal 200 se settlea. Un bloqueo 403 no. Un refusal escrito por el modelo se settlea como cualquier respuesta.

Bajo el scheme exact es todo o nada. Bajo upto, el vendedor puede settlear cualquier monto hasta el máximo autorizado. La spec del scheme dice que el monto settleado "MAY be 0 (no charge if no usage occurred)", y el binding EVM agrega que un settlement de cero no requiere transacción on-chain. El SDK lo expone como setSettlementOverrides, que acepta unidades atómicas, un porcentaje o un monto en dólares. Su propio comentario advierte que un monto distinto "is only valid in schemes that support partial settlement, such as upto". Hicimos el caso de metering para upto en nuestro post sobre upto. Los refusals son su ejemplo más filoso.

Pon las reglas de los proveedores junto a la regla del middleware y los desajustes quedan a la vista:

Qué significa para LLM4Agents

Somos el vendedor en el medio de cada una de esas filas. Tenemos las cuentas upstream, elegimos el formato de respuesta y corremos el settlement. Los agentes no ven nada de lo que decide la factura.

Nuestras respuestas usan el formato Chat Completions, así que la categoría del refusal ya no está cuando la respuesta sale de nosotros, igual que en todas las capas que leímos. Nuestro camino walk-up decide qué settlear a partir del costo medido de la llamada, y nada en ese cálculo mira por qué terminó la llamada. Hoy un refusal es una venta. Todavía no medimos qué reporta nuestro upstream para un refusal que no cobró. Si reporta conteos de tokens y ningún costo, que es como Anthropic dice que se ve un refusal no cobrado, cualquier precio calculado a partir de tokens le cobraría a un agente por una llamada que nadie nos cobró. Es lo primero que hay que probar.

El libro contable de la cuenta es la amenaza mayor. Cada agente que atendemos llega al proveedor a través de cuentas que controlamos. Sin un identificador por agente en el request, la escalera de sanciones del proveedor ve un solo cliente. Un agente tanteando un clasificador pone en riesgo el acceso de todos los demás.

La oportunidad es la imagen en espejo. Un agente no puede tener un workspace, canjear un token de credit de cinco minutos, leer una categoría y ponerle precio, ni llevar un identificador en el que el proveedor confíe. Un gateway puede hacer las cuatro cosas. Nuestras cadenas de fallback ya manejan errores. Un refusal es la única falla que no cubren, porque llega como un éxito.

Cómo mantenerse en la frontera

En orden de costo y urgencia.

1. Clasificar antes de settlear. Detectar cada forma de refusal antes de la decisión de settlement: stop_reason: "refusal", finish_reason: "content_filter", un message.refusal no vacío y los códigos bio_policy y cyber_policy. Registrarlo como una señal propia. Un refusal es un HTTP 200, así que el monitoreo por tasa de errores nunca lo ve.

2. Settlear un refusal por lo que costó. Bajo upto, un refusal no cobrado antes del output settlea 0, una categoría cobrada settlea el cargo upstream del input y un refusal a mitad de stream settlea lo que cobró el upstream. Bajo exact, saltarse el settlement es la única forma de no cobrar nada. Nunca settlear una cotización del peor caso por un content vacío.

3. Transportar la categoría. Llenar message.refusal en vez de dejarlo vacío, y agregar la categoría y el monto cobrado a la respuesta y al recibo, por ejemplo como un header X-Refusal-Category. El nombre lo elegimos nosotros; lo que importa es la señal.

4. Hacer inequívocos los bloqueos de política. Devolver los errores de política de OpenAI como un 403 con error_type: "refusal" y una indicación de no reintentar. Defendimos señales de reintento explícitas en nuestra auditoría de 402 vs 429. Un bloqueo bio reintentado es un segundo bloqueo idéntico, y cae en la misma cuenta.

5. Enviar un identificador por agente que fijemos nosotros. Derivar un safety_identifier y un metadata.user_id de Anthropic a partir de un hash de la wallet que paga o del ID del agente. Sobrescribir cualquier valor que mande el cliente, para que un agente no pueda rotarlo y esquivar la sanción.

6. Fallback ante refusals opt-in y consciente del credit. Dejar que una cadena models trate un refusal como disparador. Donde la cadena coincida con los destinos permitidos de Anthropic, pasar los modelos de la propia cadena como lista fallbacks nombrada para que aplique el credit, y reportar cada intento desde usage.iterations en el recibo. No usar routing "default" detrás de una cotización: puede elegir un modelo fuera de la cadena, y Opus 4.8, destino permitido de Opus 5.5, cuesta $5 por millón de tokens de input contra los $4 de Opus 5.5. La cadena ya se cotiza en su eslabón más caro, así que los fallbacks nombrados cambian el monto settleado, no la cotización.

7. Lint de categorías cobradas. Cuando un request a un modelo Claude con clasificadores trae un response schema o un tool input con una propiedad thinking, reasoning o trace, devolver una advertencia junto con el 402. Pedir un 402 es gratis. Eso lo convierte en el lugar más barato para avisarle a un agente que su prompt coincide con un patrón que se cobra antes de cualquier output.

Paga por llamada, en stablecoins, sobre una API compatible con OpenAI

Un 402, una firma, más de 345 modelos. Sin suscripción, sin mínimo.

Registra tu agente