Todos los artículos
Referencia de la APIAPI de PolymarketDepuraciónCLOB

Errores de la API de Polymarket: cada código, explicado

Los mensajes de error de Polymarket son escuetos, y los que rompen tu bot a las 3 de la mañana suelen ser justo los que no aparecen en la documentación. Aquí tienes la referencia completa: errores documentados, no documentados y qué hacer realmente con cada uno.

12 min de lectura

Todos los errores de la API CLOB de Polymarket vuelven con la misma forma (un objeto JSON con un único campo error), lo que es admirablemente coherente y no sirve de nada cuando intentas averiguar por qué tu orden acaba de desaparecer.

{
  "error": "<message>"
}

Esta página los explica. Cubre los errores documentados del CLOB, los códigos de estado y sus causas reales y, la parte que no encontrarás en la documentación oficial, los errores con los que la gente se topa en producción y que Polymarket nunca ha puesto por escrito.

Cada mensaje documentado tiene además su propia página con causas y un veredicto sobre si reintentar, recogidas en el índice de errores de Polymarket.

Referencia rápida de códigos de estado

EstadoSignificadoCausas comunes
400Bad RequestParámetros no válidos, payload mal formado, incumplimiento de una regla de negocio
401UnauthorizedClave de API ausente o no válida, firma HMAC incorrecta, marca de tiempo caducada
404Not FoundEl mercado no existe, orden no encontrada, ID de token no reconocido
425Too EarlyEl motor de matching se está reiniciando: reintenta con backoff
429Too Many RequestsLímite de tasa superado: aplica backoff exponencial
500Internal Server ErrorError inesperado del servidor: reintenta con backoff
503Service UnavailableExchange en pausa, o bloqueado por el modo cancel-only / post-only

La sustitución de códigos de estado que te confundirá

La API CLOB reescribe los códigos de estado según el contenido del mensaje. Cualquier mensaje de error que contenga "not found" devuelve 404, cualquiera que contenga "unauthorized" devuelve 401 y cualquiera que contenga "context canceled" devuelve 400, sea cual sea el código de estado original. Si un código de estado parece contradecir el mensaje, este es el motivo. Ramifica tu gestión de errores según el texto del mensaje, no según el número.

401: errores de autenticación

Unauthorized/Invalid api key

El error de Polymarket más buscado. Tu clave de API falta, ha caducado o no es válida. En la práctica casi nunca es una clave realmente mala; es una de estas causas:

  1. Solo envías parte del conjunto de credenciales. La autenticación L2 de Polymarket necesita la key, el secret y la passphrase juntos. Un fallo habitual es rellenar POLY_API_KEY y POLY_PASSPHRASE pero dejar el secret sin definir: el cliente envía una solicitud bien formada pero imposible de firmar.
  2. El reloj de tu sistema se ha desfasado. La firma incluye una marca de tiempo, y un reloj desfasado más de unos segundos produce una firma que el servidor rechaza como no válida. Es la causa que la gente encuentra la última y es tristemente común en VMs y contenedores.
  3. Derivaste la clave con una wallet distinta de la que usas para operar. Las claves están vinculadas a la dirección de firmante que las creó.
  4. Llamas a un endpoint autenticado con cabeceras L1 donde se esperan L2, o al revés.

Invalid L1 Request headers

Tus cabeceras de autenticación L1 (el conjunto de firma EIP-712) están mal formadas, o la firma no coincide con la dirección que dices ser. Comprueba que firmas con la misma clave privada que la dirección de la cabecera y que tu domain separator coincide con la cadena en la que estás (Polygon, chain ID 137). Una firma válida para otro chain ID sigue siendo una firma válida, solo que no para este servidor.

Could not create api key / Could not derive api key!

Son los errores detrás de la búsqueda "polymarket unable to generate api credentials". Los dos los devuelven los endpoints de autenticación cuando falla la creación o la derivación de la clave. Could not derive api key! en GET /auth/derive-api-key suele significar que aún no existe ninguna clave para ese firmante: derive devuelve una clave existente, no crea una. Crea primero la clave con POST /auth/api-key y derívala en las ejecuciones posteriores.

El patrón derivar-y-si-no-crear

En lugar de guardar las claves, la mayoría de los bots en producción intentan primero derive y, si falla, recurren a create. Es idempotente entre reinicios y evita acumular claves huérfanas; los endpoints de autenticación están limitados a 100 req / 10s, así que de todos modos no te interesa crear una clave en cada arranque.

400: errores de rechazo de órdenes

Se devuelven cuando una orden pasa la validación de transporte pero incumple las reglas de negocio. Aparecen en el cuerpo de la respuesta de POST /order y POST /orders.

Mensaje de errorQué significa
the order signer address has to be the address of the API KEYLa clave que firma la orden no es la clave que la orden dice que la firmó. Estás mezclando credenciales, normalmente una clave obsoleta de una wallet anterior.
the order owner has to be the owner of the API KEYLa dirección maker de la orden no coincide con la dirección a la que pertenece la clave de API.
order {id} is invalid. Price ({price}) breaks minimum tick size rule: {tick}Tu precio no está en la cuadrícula de ticks del mercado. Llama a GET /tick-size y redondea; no supongas 0.01.
order {id} is invalid. Size ({size}) lower than the minimum: {min}Tamaño de orden por debajo del mínimo del mercado.
not enough balance / allowanceSaldo de pUSD insuficiente, o nunca concediste un allowance al contrato del exchange. Ambas cosas son necesarias.
invalid post-only order: order crosses bookTu orden post-only tomaría liquidez de inmediato. Cambia el precio para que quede en reposo.
order couldn't be fully filled. FOK orders are fully filled or killed.Fill-or-Kill encontró liquidez insuficiente. Se rechaza la orden entera.
no orders found to match with FAK order.Fill-and-Kill no encontró ninguna contrapartida. Se necesita al menos una.
invalid expirationLa marca de tiempo de expiración está en el pasado o mal formada.
order {id} is invalid. Duplicated.Se envió la misma orden dos veces.
order canceled in the CTF exchange contractLa orden se canceló on-chain.
'{address}' address bannedLa dirección tiene prohibido operar.
'{address}' address in closed only modeLa dirección solo puede cerrar posiciones existentes.

El tamaño del tick es propio de cada mercado y cambia

El rechazo silencioso de órdenes más común es una infracción del tamaño de tick. El tamaño del tick varía entre mercados y puede reducirse a medida que el mercado madura: un precio válido la semana pasada puede no serlo hoy. Consulta GET /tick-size para cada mercado y redondea en lugar de fijar una cuadrícula en el código.

Las órdenes por lotes fallan de otra forma

En POST /orders, los fallos de cada orden vuelven dentro del array de la respuesta 200 con campos errorMsg individuales, no como un error de nivel superior. Un 200 no significa que se aceptaran todas las órdenes del lote. Recorre el array y revisa cada entrada.

425: Too Early

Un código de estado poco habitual que confunde a la gente porque apenas se usa en el resto de la web. En Polymarket significa que el motor de matching se está reiniciando. Tu solicitud llegó durante la ventana en la que el exchange vuelve a arrancar.

Este es de verdad transitorio y de verdad seguro de reintentar: probablemente sea el error de la plataforma más apropiado para reintentar. Espera y vuelve a intentarlo; no lo trates como un fallo y no alertes por un caso aislado.

503: el exchange está en un modo restringido

Polymarket puede poner el exchange en modos restringidos. No son fallos de tu lado, y por mucho que reintentes la misma solicitud no servirá de nada hasta que se levante el modo.

MensajeLo que todavía puedes hacer
Trading is currently disabled. Check polymarket.com for updatesNada. No se acepta ninguna orden, incluidas las cancelaciones.
Trading is currently cancel-only. New orders are not accepted, but cancels are allowed.Cancelar órdenes existentes. No puedes abrir nuevas.
post-only mode: only post-only orders and cancels are allowedCancelar, o colocar órdenes con postOnly: true. Las órdenes que toman liquidez se rechazan.

El modo post-only es el que hay que gestionar bien, porque te dice exactamente cuándo volver. La respuesta incluye code: "post_only_mode" y retry_after_seconds, y el mismo retraso se envía en la cabecera Retry-After.

{
  "error": "post-only mode: only post-only orders and cancels are allowed",
  "code": "post_only_mode",
  "retry_after_seconds": 79
}

El modo cancel-only puede atrapar a un bot de market making

Si la ruta de apagado de tu bot vuelve a cotizar antes de cancelar, el modo cancel-only rechazará la nueva cotización y tu bot puede entrar en bucle en lugar de cerrar posiciones. Gestiona el 503 cancelando primero y solo después decide si volver a entrar.

Errores que no están en la documentación

Aquí es donde se va la mayor parte del tiempo real de depuración. Los siguientes no aparecen en la referencia de códigos de error de Polymarket porque no los genera la aplicación CLOB: vienen del edge, de la red o de tu biblioteca cliente. Saber qué capa produjo un error te dice dónde buscar.

"The server was unable to process your request"

El error de Polymarket más buscado que no está en la documentación. Es un mensaje de la capa de edge, no un error de la API CLOB: es lo que recibes cuando la solicitud nunca llegó a la aplicación, o nunca volvió de ella de forma limpia. En la práctica, las causas habituales son:

  • Una solicitud mal formada que el edge rechaza antes de enrutarla: un payload demasiado grande, una cabecera incorrecta o un método HTTP no válido para la ruta.
  • Un fallo transitorio aguas arriba mientras el servicio se vuelve a desplegar o está bajo carga.
  • Limitación de tasa sostenida. Como Cloudflare limita poniendo en cola en lugar de rechazar, un cliente muy por encima del límite puede acabar con solicitudes que agotan el tiempo en el edge en lugar de devolver un 429 limpio.

Trátalo como reintentable con backoff, pero si es persistente y no ocasional, comprueba primero tu tasa de solicitudes (consulta la referencia de límites de tasa) y después el tamaño de tu payload.

403 Forbidden

Un 403 de Polymarket normalmente no es un problema de autenticación, y eso es lo que lo hace confuso. Por lo general es el edge bloqueando la solicitud. Los desencadenantes comunes son las restricciones geográficas en los endpoints de trading, los rangos de IP de centros de datos y VPN sometidos a verificación, y la falta de cabeceras (o cabeceras poco parecidas a las de un navegador) en solicitudes que el edge espera que vengan de un cliente.

Si un 403 aparece solo desde tu VM en la nube y no desde tu portátil, es un problema de reputación de la IP, no del código. Si aparece en los endpoints de trading pero no en los de datos de mercado, es geográfico.

Errores de SSL, TLS y certificados

"polymarket ssl error", "polymarket certificate error" y "polymarket https error" son casi siempre del lado del cliente. Los certificados de Polymarket están bien; lo que falla es algo entre tú y ellos. Comprueba, por orden: un bundle de CA desactualizado (muy común en imágenes Docker antiguas y entornos Python congelados), un proxy corporativo que inspecciona TLS y sustituye el certificado por el suyo, y un reloj del sistema tan desfasado que los certificados parecen aún no válidos o caducados.

# 1. Does TLS work at all, outside your app's HTTP client?
curl -sS -o /dev/null -w "%{http_code} %{ssl_verify_result}\n" \
  https://clob.polymarket.com/ok

# 2. Is your CA bundle current? (Python)
python3 -c "import certifi, os; print(certifi.where()); print(os.path.getmtime(certifi.where()))"

# 3. Is your clock right? Certificate validation depends on it.
date -u

"Service not ready"

Un mensaje de estado de arranque: el servicio está lo bastante levantado para responder, pero no listo para servir. En la práctica trátalo como un 425: espera y reintenta. Debería resolverse en segundos, y no es algo que puedas arreglar desde el cliente.

"Order manager not ready"

Un mensaje de estado de arranque del motor de matching, pariente cercano de 425 Too Early. El servicio es accesible, pero la capa de gestión de órdenes no ha terminado de arrancar, así que aceptará tu conexión y rechazará tu orden. Es transitorio y seguro de reintentar con backoff, pero tómalo como una señal para dejar de enviar durante unos segundos en lugar de insistir, porque un reinicio suele significar que el libro está a punto de cambiar bajo tus pies.

Si lo ves de forma persistente y no en ráfagas, revisa el estado de Polymarket antes de depurar tu propio código: no hay nada que arreglar del lado del cliente.

"Couldn't get a quote"

Suele significar que no hay liquidez en reposo en el lado al que pediste precio, no que algo esté roto. En los mercados Up/Down poco líquidos cerca del vencimiento, un lado se vacía con frecuencia (nadie vende Up a ningún precio cuando Up es seguro), así que una solicitud de cotización no devuelve nada. Nuestros propios datos muestran que es habitual: en una muestra de mercados BTC de 5 minutos, 1,454 de 8,510 tenían el libro de asks vacío en un lado 60 segundos antes del vencimiento.

Trátalo como “no hay mercado” y no como un error: omite la operación y no reintentes en un bucle cerrado. Si necesitas saber con qué frecuencia ocurre en una serie que operas, las páginas de datos de mercado muestran la liquidez por intervalo.

Excepciones de la biblioteca cliente

Errores como PolyApiException[status_code=None, error_message=request exception!] vienen del cliente de Python, no del servidor. status_code=None es la pista: nunca se recibió ninguna respuesta HTTP, así que es un fallo a nivel de conexión (DNS, TLS, timeout o un socket caído) que aparece como una excepción de la biblioteca. Depúralo como un problema de red, no de la API. El mismo razonamiento se aplica a BuilderApiKeyCreds invalid authorization 401 en el cliente del relayer, que significa que no se aceptaron las credenciales de builder pasadas al cliente; vuelve a derivarlas en lugar de reutilizar un conjunto en caché.

Una política de reintentos que lo gestiona todo

La conclusión práctica es que los errores de Polymarket se dividen en tres grupos, y mezclarlos es lo que hace frágiles a los bots: reintentar sin más, reintentar tras un retraso concreto y no reintentar nunca.

CategoríaCódigos / mensajesAcción
Transitorio425, 500, Service not ready, errores de conexiónReintentar con backoff exponencial + jitter
Limitado por tasa429Reintentar tras Retry-After; si no está, backoff con jitter
Restringido por modo503 post-onlyEsperar retry_after_seconds y luego reintentar
Restringido por modo503 cancel-only / desactivadoDejar de abrir posiciones; cancelar si está permitido; consultar con poca frecuencia
Terminal400 de validación, 401, 404No reintentar: corrige la solicitud o las credenciales
type Decision =
  | { retry: true; delayMs: number }
  | { retry: false; reason: string };

function classify(status: number, body: { error?: string; code?: string; retry_after_seconds?: number }, attempt: number): Decision {
  const msg = (body.error ?? "").toLowerCase();
  const backoff = Math.min(2 ** attempt * 250, 8000);
  const jittered = Math.random() * backoff;

  // Never retry — the request itself is wrong.
  if (status === 401) return { retry: false, reason: "auth: check key, secret, passphrase and clock drift" };
  if (status === 404) return { retry: false, reason: "not found" };
  if (status === 400) return { retry: false, reason: `validation: ${body.error}` };

  // Mode-restricted — the server tells you when to come back.
  if (status === 503 && body.code === "post_only_mode") {
    return { retry: true, delayMs: (body.retry_after_seconds ?? 60) * 1000 };
  }
  if (status === 503) return { retry: false, reason: "exchange paused or cancel-only" };

  // Transient — safe to retry.
  if (status === 425 || status === 429 || status >= 500) return { retry: true, delayMs: jittered };
  if (msg.includes("service not ready")) return { retry: true, delayMs: jittered };

  return { retry: false, reason: `unhandled status ${status}` };
}

Registra el mensaje, alerta por la categoría

Alertar por los strings de error literales genera ruido, porque los mensajes de Polymarket incluyen IDs de órdenes y precios. Alerta por la categoría: un pico de 400 terminales significa que has desplegado un bug; un pico de 429 significa que tienes que ir más despacio; un pico de 425 significa que Polymarket se está reiniciando y no debes hacer nada.

Errores de los que no puedes salir depurando

Algunas cosas que parecen errores simplemente no están soportadas. Polymarket no tiene un endpoint de libro de órdenes histórico, así que no hay nada a lo que llamar mal. El libro de un mercado resuelto devuelve 404 porque Polymarket deja de servirlo cuando el mercado se liquida, aunque tu ID de token sea correcto.

Si te estás topando con esos muros, no estás depurando una integración: te falta una fuente de datos. PolyTest graba snapshots puntuales de los mercados cripto Up/Down de Polymarket mientras están activos, con la profundidad completa del libro de órdenes, así que el historial sigue ahí después de la resolución. Nuestra propia referencia de errores cubre las formas de error de la API de PolyTest, que en comparación son deliberadamente aburridas.

Preguntas frecuentes

¿Qué significa "Unauthorized/Invalid api key" en Polymarket?
Significa que tu clave de API falta, ha caducado o no es válida, pero en la práctica la causa suele ser una de cuatro: envías un conjunto de credenciales incompleto (la key, el secret y la passphrase son obligatorios), el reloj de tu sistema se ha desfasado lo suficiente como para invalidar la firma de la solicitud, derivaste la clave con una wallet distinta de la que usas para operar, o envías cabeceras L1 donde se esperan cabeceras L2.
¿Qué es el error 425 de Polymarket?
HTTP 425 Too Early significa que el motor de matching de Polymarket se está reiniciando y tu solicitud llegó durante esa ventana. Es transitorio y seguro de reintentar con backoff exponencial. No vale la pena alertar por un 425 aislado.
¿Por qué Polymarket dice "The server was unable to process your request"?
Es un mensaje de la capa de edge y no un error documentado de la API CLOB, lo que significa que la solicitud nunca llegó a la aplicación, o nunca volvió de ella, de forma limpia. Las causas habituales son una solicitud mal formada rechazada antes de enrutarla, un fallo transitorio aguas arriba o una limitación de tasa sostenida: como Polymarket limita poniendo en cola en lugar de rechazar, un cliente muy por encima del límite puede ver timeouts en el edge en lugar de 429 limpios.
¿Por qué recibo un 403 de la API de Polymarket?
Un 403 de Polymarket suele ser el edge bloqueando la solicitud, no un fallo de autenticación. Los desencadenantes comunes son las restricciones geográficas en los endpoints de trading, los rangos de IP de centros de datos o VPN sometidos a verificación y la falta de cabeceras parecidas a las de un navegador. Si ocurre desde una VM en la nube pero no desde tu portátil, es la reputación de la IP; si ocurre en los endpoints de trading pero no en los de datos de mercado, es geográfico.
¿Cómo soluciono "the order signer address has to be the address of the API KEY"?
La clave que firma tu orden no coincide con la clave que la orden dice que se usó. Significa que estás mezclando credenciales, normalmente una clave de API obsoleta guardada en caché de una wallet anterior. Vuelve a derivar tus credenciales de API para la wallet con la que realmente operas y asegúrate de que la dirección maker de la orden coincide con la dirección propietaria de la clave.
¿Qué significa "order manager not ready" en Polymarket?
Es un mensaje de estado de arranque del motor de matching: el servicio es accesible, pero la capa de gestión de órdenes no ha terminado de arrancar, así que acepta la conexión y rechaza la orden. Es transitorio y está muy relacionado con HTTP 425 Too Early. Reintenta con backoff, pero pausa los envíos unos segundos en lugar de insistir, porque un reinicio suele significar que el libro está a punto de moverse. Si ocurre de forma persistente, es un problema del lado de Polymarket, no un bug del cliente.
¿Por qué Polymarket dice que no pudo obtener una cotización?
Casi siempre porque no hay liquidez en reposo en el lado al que pediste precio, no porque algo esté roto. En los mercados Up/Down poco líquidos cerca del vencimiento, un lado se vacía con frecuencia: nadie ofrece Up cuando Up es seguro. En una muestra de mercados BTC de 5 minutos, 1,454 de 8,510 tenían el libro de asks vacío en un lado 60 segundos antes del vencimiento. Trátalo como “no hay mercado” y omite la operación en lugar de reintentar en bucle.
¿Debo reintentar automáticamente los errores de la API de Polymarket?
Solo algunos. Reintenta los 425, 429, la serie 500 y los errores de conexión con backoff exponencial más jitter. Reintenta el modo post-only 503 tras el valor retry_after_seconds que indica la respuesta. No reintentes nunca los errores de validación 400, los errores de autenticación 401 ni los 404: requieren corregir la solicitud o las credenciales, y reintentar solo quema presupuesto de límite de tasa.

Obtén los datos históricos que Polymarket no guarda

PolyTest registra los mercados cripto Up/Down de Polymarket mientras están activos: 240M+ snapshots con 8 niveles de profundidad del libro de órdenes, marcas de tiempo por debajo del segundo y mercados resueltos conservados. Empieza con una prueba gratuita de 3 días.

Sigue leyendo