Volver al blog
KalshiComplianceBunRegulación

Kalshi en Utah: cuando tu código se convierte en acusación penal

05 de noviembre de 2026·7 min de lectura·Diego Horvatti

Los dos fundadores de Kalshi fueron acusados de un delito grave en Utah. El motivo es una app de predicciones que funcionaba con normalidad en el resto de Estados Unidos. Kalshi es la plataforma donde compras contratos de "sí" o "no" sobre eventos reales: elecciones, tasas de interés, resultados de partidos. Utah miró eso y vio apuestas. Y Utah prohíbe toda forma de apuesta, incluida la lotería. Ahí la historia se puso rara: el gobierno de Trump demandó al estado de Utah para proteger a Kalshi, según Ars Technica.

Parece cosa de abogados. No lo es. Aquí hay una lección muy práctica para quien escribe software que atiende a gente en más de un lugar.

¿Qué le pasó a Kalshi en Utah?

El resumen cabe en cuatro frases.

Kalshi está regulada a nivel federal por la CFTC, la agencia estadounidense que supervisa derivados y mercados de futuros. Para la empresa, un contrato sobre "¿gana el equipo X el domingo?" es un instrumento financiero, no una apuesta. Varios estados no están de acuerdo, sobre todo cuando el contrato es sobre deportes. Utah fue el que más lejos llegó: en lugar de mandar una carta o abrir un proceso civil, presentó una acusación penal contra la empresa y contra sus fundadores, Tarek Mansour y Luana Lopes Lara.

El gobierno federal respondió demandando al estado. El argumento es el de la preeminencia federal: si la ley federal regula estos mercados, un estado no puede criminalizar el mismo producto por su cuenta.

Quién gana esta pelea lo decidirán los tribunales, probablemente en más de una instancia. No voy a fingir que sé el resultado. Pero para quien programa, el resultado importa menos que la pregunta que plantea el caso.

¿Por qué debería importarle esto a un dev?

Porque casi todo producto digital hoy funciona en varias jurisdicciones a la vez, y nadie en el equipo piensa en eso hasta que es tarde.

Haces deploy una vez y la app aparece en el mundo entero. La ley no funciona así. Cada estado, cada país, a veces cada ciudad tiene su regla. Lo que es legal en Nueva York puede ser delito en Salt Lake City. Lo que está bien en Brasil puede necesitar licencia en Portugal.

Lo tratamos como un problema del área legal. Pero quien decide si un usuario de Utah ve o no ve el botón de comprar es un if en tu código. ¿Ese if existe? ¿Está bien? ¿Quién lo probó?

La ley tiene fronteras. El deploy no. Lo que queda en medio es responsabilidad de tu código.

Y hay un detalle que asusta: la acusación fue contra personas, no solo contra la empresa. Un fundador suele entender el riesgo cuando firma. El dev que implementó la feature, en general, ni se enteró de que existía un riesgo.

Lo que "regulado a nivel federal" no te garantiza

Este es el punto que me parece más útil para quien está empezando un producto.

Kalshi no es una startup que ignoró la ley. Pasó años peleando para conseguir la aprobación de la CFTC. Tiene la licencia. Aun así, un estado decidió que esa licencia no vale en su territorio.

Traducido a nuestro mundo:

  • Tener una cuenta aprobada en Stripe no significa que tu producto sea legal en todos los países donde opera Stripe.
  • Estar en la App Store no significa que la app cumpla la ley de todos los lugares donde se puede descargar.
  • Cumplir la LGPD de Brasil no te cubre en California, y lo contrario tampoco.

La licencia es necesaria. Pero no alcanza. Es el comienzo de la conversación. Si tu producto toca dinero, salud, apuestas, contenido adulto, criptomonedas o datos sensibles, parte de la base de que alguien, en algún lugar, no va a estar de acuerdo contigo.

Cómo aparece esto en el código: geobloqueo de verdad

En la práctica, empresas como Kalshi bloquean o limitan funcionalidades por región. Si algún día necesitas hacer algo parecido, la forma perezosa y equivocada es ocultar el botón en el frontend. Eso no bloquea nada. Cualquiera con DevTools abierto llama a la API directamente.

El bloqueo tiene que estar en el servidor, en el punto donde ocurre la acción. Un ejemplo mínimo con Bun:

// regiones donde la funcionalidad no puede existir
const BLOCKED = new Set(["US-UT", "US-NV"]);

Bun.serve({
  port: 3000,
  fetch(req) {
    const url = new URL(req.url);
    // la CDN inyecta la región; el nombre del header cambia según el proveedor
    const region = req.headers.get("x-geo-region") ?? "UNKNOWN";

    if (url.pathname.startsWith("/api/orders")) {
      if (region === "UNKNOWN" || BLOCKED.has(region)) {
        return Response.json(
          { error: "No disponible en tu región" },
          { status: 451 },
        );
      }
    }
    return new Response("ok");
  },
});

Tres cosas para notar en este fragmento.

Primero, el status 451 Unavailable For Legal Reasons. Existe de verdad, viene del RFC 7725, y casi nadie lo usa. Úsalo. Deja claro en el log por qué cayó la petición, y eso ayuda mucho cuando alguien del área legal pregunta "¿cuántas personas de Utah intentaron comprar?".

Segundo, una región desconocida se bloquea. Ese es el comportamiento seguro por defecto. Si el header no llegó, no sabes dónde está el usuario, y "no sé" no puede convertirse en "adelante".

Tercero, la IP sola es débil. Una VPN lo resuelve en dos clics. Para un producto regulado de verdad, la ubicación se combina con dirección verificada, documento y a veces el GPS del celular. El código de arriba es el piso, no el techo.

La lista de regiones no es configuración, es decisión de negocio

Aquí va mi opinión fuerte: esa lista de regiones bloqueadas no puede quedar enterrada en una constante que solo conoce el dev.

Ya lo vi pasar en un proyecto de un cliente. Una regla de "no vender en tal estado" vivía en un archivo de config que nadie abría desde hacía dos años. La ley cambió, el área legal avisó a ventas, ventas no avisó a nadie. La app siguió vendiendo.

Lo que yo haría hoy:

  • La lista vive en un lugar versionado y con dueño, ya sea un repositorio, una base de datos o un feature flag con historial.
  • Cada cambio en la lista tiene un responsable que no es solo el dev.
  • Existe un log de a quién se bloqueó y cuándo, porque ese log es tu prueba de buena fe si alguien pregunta después.

Nada de esto es complicado. Es una tabla, un endpoint y un commit. Lo difícil es acordarse de que tiene que existir antes de que alguien lo necesite.

¿Y si gana el gobierno federal?

Puede que la Justicia diga que la ley federal pesa más y que Utah no puede hacer esto. Kalshi vuelve a operar tranquila y la acusación se cae.

Incluso en ese escenario, la lección para el dev sigue igual. El caso muestra que un producto puede estar en regla sobre el papel y aun así ser blanco de un proceso penal durante años. El costo de tener razón en un tribunal es enorme. El costo de tener un geobloqueo decente desde el principio es una tarde de trabajo.

También vale recordar que las reglas políticas cambian con el gobierno. Lo que el gobierno federal defiende hoy puede no ser lo que defienda dentro de cuatro años. Un código que depende de "el gobierno está de nuestro lado" es un código con fecha de vencimiento.

Lo que me llevo de esto

No tengo una opinión formada sobre si un mercado de predicciones es apuesta o derivado. Creo que las dos lecturas tienen argumentos, y por eso el caso está en los tribunales y no en Twitter.

La parte que me interesa es más simple. La mayoría de nosotros nunca va a ser acusada de un delito en Utah, por suerte. Pero casi todos ya escribimos, o vamos a escribir, código que decide quién puede hacer qué y desde dónde. Ese código es tan crítico como el de autenticación, y suele recibir una décima parte de la atención.

Si estás construyendo algo que maneja dinero o datos sensibles, invierte la tarde. Haz el bloqueo en el servidor, usa el 451, bloquea lo desconocido y dale un dueño a la lista. Es el tipo de cuidado que intento poner en los proyectos que construyo, incluso cuando nadie lo pidió.

Resumen para LinkedIn

Los fundadores de Kalshi fueron acusados penalmente en Utah por una app que funcionaba con normalidad en el resto de EE. UU.

La empresa tiene licencia federal. Aun así, el estado decidió que esa licencia no vale en su territorio.

El deploy no tiene fronteras, pero la ley sí. Y quien decide si un usuario de Utah ve el botón de comprar es un if en tu código.

Ocultar el botón en el frontend no bloquea nada. El bloqueo tiene que estar en el servidor, devolver 451 y tratar una región desconocida como bloqueada.

La lista de regiones bloqueadas es una decisión de negocio, no una constante olvidada en un archivo de config. Necesita un dueño, un historial y un log.

Escribí el artículo completo con el código y lo que yo haría hoy. El enlace está en los comentarios, para quien construye productos que manejan dinero o datos sensibles.

#DesarrolloDeSoftware #Compliance #Backend #Startups #Tecnología