Una API de monedero cripto no es un único producto. Normalmente son tres capas distintas: una API de datos indexados que devuelve saldos, tokens e historial de una dirección; una capa de firma que mantiene las claves privadas o las participaciones de clave bajo tu control; y una capa RPC que lee el estado de la cadena y difunde transacciones firmadas. Tratar estas capas como una caja negra es la causa más común de saldos desactualizados, difusiones fallidas y errores de custodia. Este artículo te ofrece un modelo mental, comprobaciones ejecutables para cada capa, un procedimiento de medición reproducible y pasos para solucionar problemas, y después señala la selección concreta de endpoints cuando la elección depende del proveedor.
Qué cubre realmente una API de monedero cripto
La expresión api de monedero cripto se usa para al menos tres interfaces diferentes. Una API de datos de monedero recibe una dirección y devuelve JSON estructurado: saldos nativos, tenencias de tokens, NFT, transferencias y, a veces, posiciones DeFi o cifras de ganancias y pérdidas. Una API de monedero como servicio crea monederos, gestiona claves o participaciones de clave y expone operaciones de envío y recepción. Una API RPC expone métodos JSON-RPC como eth_getBalance, eth_getTransactionCount, eth_sendRawTransaction y eth_getTransactionReceipt directamente contra un nodo.
Estas capas fallan de formas distintas. Los datos indexados pueden retrasarse respecto a la cabeza de la cadena segundos o bloques. La firma puede fallar por reutilización de nonce, chain ID incorrecto o una política de gestión de claves. El RPC puede fallar por límites de tasa, reorganizaciones o un nodo atrasado. Si construyes una función de monedero sobre un único proveedor sin saber qué capa estás llamando, no puedes diagnosticar cuál de estos problemas está ocurriendo.
Este artículo asume que estás construyendo una aplicación que muestra el estado del monedero y envía transacciones, y que quieres mantener el material de claves bajo tu propio control. No asume una cadena ni un proveedor concretos. Cuando la elección de un endpoint concreto importe, usa el Asistente RPC de OnFinality en lugar de fijar un proveedor copiado de un artículo de blog.
- Capa de datos: entra una dirección, sale una cartera e historial; normalmente indexada y en caché.
- Capa de firma: entra una transacción sin firmar, sale una transacción firmada; las claves nunca salen de tu perímetro.
- Capa RPC: lecturas de cadena y difusión de transacciones; la más cercana al nodo y a la cabeza de la cadena.
Requisitos previos y supuestos antes de integrar
Necesitas un endpoint RPC para cada cadena que soportes, una clave de API o credencial para cualquier proveedor de datos indexados, y una decisión de gestión de claves: claves no custodiales en manos del usuario, claves en tu backend dentro de un KMS o HSM, o un acuerdo de monedero como servicio. Cada elección cambia tu superficie de cumplimiento y tu historia de recuperación.
También debes decidir tu fuente de verdad. Para los saldos, la cadena es autoritativa pero costosa de consultar a escala; un indexador es rápido pero con consistencia eventual. Para el estado de una transacción, el recibo del nodo RPC es autoritativo, pero debes gestionar reorganizaciones. Deja escritas estas decisiones antes de escribir código, porque determinan qué API llamas para cada pantalla de tu producto.
Por último, confirma el soporte de cadenas de forma explícita. No asumas que un proveedor de datos y un proveedor RPC soportan las mismas redes, testnets o profundidad de archivo. Consulta la lista de redes de las cadenas que planeas lanzar y verifica la disponibilidad de testnet por separado de la de mainnet.
- Una URL RPC por cadena, guardada en un gestor de secretos, nunca en el código del cliente.
- Un modelo de custodia documentado y un procedimiento de rotación de claves.
- Un objetivo de frescura declarado, por ejemplo saldos con una antigüedad máxima de 30 segundos en la interfaz.
- Una política de reorganizaciones: cuántas confirmaciones antes de marcar un depósito como final.
Modelo mental: indexador, firmante y nodo como servicios separados
Imagina tres servicios detrás de tu interfaz de monedero. El indexador se suscribe a bloques, analiza logs y trazas, y escribe filas indexadas por dirección. El firmante guarda claves y produce firmas sobre transacciones serializadas. El nodo responde a llamadas JSON-RPC y propaga transacciones a sus pares.
Una ruta de lectura para una pantalla de cartera va así: interfaz → tu backend → indexador. Una ruta de escritura va así: interfaz → tu backend construye una transacción sin firmar → el firmante firma → el backend llama a eth_sendRawTransaction en el nodo → el backend consulta eth_getTransactionReceipt. Mantener estas rutas separadas significa que un indexador atrasado nunca bloquea un retiro, y que un nodo ocupado nunca corrompe los saldos que muestras.
Esta separación también te permite cambiar de proveedor por capa. Podrías usar un proveedor para datos multichain indexados y otro proveedor RPC para difusión de baja latencia. El directorio de redes de OnFinality y las opciones de nodo dedicado son relevantes cuando necesitas capacidad RPC predecible en lugar de endpoints públicos compartidos.
Leer el estado del monedero mediante una API de datos indexados
La mayoría de las API de datos de monedero exponen una forma REST similar a GET /addresses/{address}/balances o una consulta GraphQL. Las rutas exactas varían según el proveedor, así que trata lo siguiente como una forma que debes adaptar, no como un contrato literal. Lo importante es lo que afirmas sobre la respuesta: qué cadena, qué altura de bloque y qué frescura tienen los datos.
Solicita o registra siempre una altura de bloque junto a los saldos. Sin ella no puedes saber si un token ausente es un saldo cero real o un indexador que no se ha puesto al día. Si el proveedor devuelve un campo synced_at o block_number, guárdalo con la respuesta y muestra la antigüedad en tu interfaz cuando supere tu umbral.
curl -s "https://WALLET_DATA_API_HOST/v1/addresses/0xYOUR_ADDRESS/balances?chain=ethereum" \
-H "Authorization: Bearer $WALLET_DATA_API_KEY" \
| jq '{block: .meta.block_number, synced_at: .meta.synced_at, tokens: [.balances[] | {symbol, amount, contract}]}'Leer el estado de la cadena directamente por JSON-RPC
Cuando necesitas el valor autoritativo en la cabeza de la cadena, llama al nodo. Las dos llamadas siguientes son JSON-RPC estándar de Ethereum y funcionan en cualquier endpoint compatible con EVM. Sustituye RPC_URL por el endpoint de tu proveedor; nunca confirmes una URL real con una clave incrustada.
Compara el saldo por RPC con el saldo indexado de la misma dirección. Una diferencia persistente suele significar que el indexador está atrasado, que la dirección está en una cadena distinta de la que crees, o que el token es un saldo de contrato que la llamada de saldo nativo no incluye.
curl -s -X POST "$RPC_URL" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"eth_getBalance","params":["0xYOUR_ADDRESS","latest"]}' | jq '.result'
curl -s -X POST "$RPC_URL" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":2,"method":"eth_blockNumber","params":[]}' | jq '.result'Construir y firmar una transacción sin exponer claves
El patrón seguro es: obtener el nonce y los parámetros de gas del nodo, construir la transacción sin firmar en tu backend, firmarla dentro de tu perímetro de claves y luego difundir los bytes en bruto. El firmante nunca debe recibir una URL RPC con acceso de escritura, y la credencial RPC nunca debe poder exportar claves.
El ejemplo de JavaScript siguiente usa ethers para construir y firmar localmente. Lee el nonce del nodo, firma con una clave cargada desde una variable de entorno e imprime la transacción en bruto. En producción, sustituye el monedero local por un firmante KMS o HSM y mantén PRIVATE_KEY fuera de la memoria del proceso siempre que sea posible.
import { JsonRpcProvider, Wallet, parseEther } from "ethers";
const provider = new JsonRpcProvider(process.env.RPC_URL);
const wallet = new Wallet(process.env.PRIVATE_KEY, provider);
const nonce = await provider.getTransactionCount(wallet.address, "pending");
const fee = await provider.getFeeData();
const tx = {
to: "0xRECIPIENT_ADDRESS",
value: parseEther("0.001"),
nonce,
chainId: (await provider.getNetwork()).chainId,
maxFeePerGas: fee.maxFeePerGas,
maxPriorityFeePerGas: fee.maxPriorityFeePerGas,
gasLimit: 21000n,
};
const raw = await wallet.signTransaction(tx);
console.log(raw);
// Broadcast separately: await provider.broadcastTransaction(raw);Verificar una difusión y confirmar la finalidad
Tras la difusión, consulta eth_getTransactionReceipt hasta que devuelva un recibo con un número de bloque, y luego espera según tu política de confirmaciones. Un recibo con status: 0x1 significa que la transacción se ejecutó correctamente; 0x0 significa que se revirtió y se consumió gas. Un recibo nulo significa que el nodo aún no ha visto la transacción, lo que puede indicar un retraso de propagación, una transacción descartada o un hueco de nonce.
Registra el hash de la transacción, el número de bloque y la marca de tiempo del primer recibo. Ese registro es el que usarás después para conciliar con tu indexador y responder a preguntas de soporte. Si el recibo nunca aparece, comprueba el nonce contra eth_getTransactionCount con la etiqueta pending antes de reenviar.
curl -s -X POST "$RPC_URL" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":3,"method":"eth_getTransactionReceipt","params":["0xYOUR_TX_HASH"]}' \
| jq '{status: .result.status, block: .result.blockNumber, gasUsed: .result.gasUsed}'Un procedimiento de medición reproducible para tu stack de API de monedero
No confíes en las afirmaciones de latencia de los proveedores para tu propia carga de trabajo. Mide las rutas que tus usuarios realmente usan. Ejecuta cada comprobación al menos 100 veces en una ventana fija, desde la misma región que tu backend, y registra p50, p95 y p99. Separa la latencia de lectura (saldo e historial) de la latencia de escritura (de la difusión al primer recibo).
Usa un script que marque con tiempo cada solicitud y luego agrega los resultados. La tabla siguiente es la forma que debes rellenar; las cifras deben venir de tu propia ejecución, no de este artículo.
- Ruta de lectura: mide el tiempo de
GET /balancesen la API de datos y deeth_getBalanceen el endpoint RPC para la misma dirección. - Ruta de escritura: mide el tiempo desde
eth_sendRawTransactionhasta el primer recibo no nulo. - Frescura: compara la altura de bloque reportada por el indexador con
eth_blockNumberen el mismo momento. - Tasa de errores: cuenta por separado los HTTP 429, los 5xx y los objetos de error JSON-RPC.
| Path | p50 (ms) | p95 (ms) | p99 (ms) | Error rate | Notes |
|------|----------|----------|----------|------------|-------|
| Indexed balances | | | | | record block height |
| RPC eth_getBalance | | | | | same address |
| Broadcast to receipt | | | | | same chain, same fee policy |
| Indexer lag (blocks) | | | | | head minus indexed |Solución de problemas comunes de las API de monedero
Los saldos parecen incorrectos o desactualizados. Compara la altura de bloque del indexador con la cabeza del RPC. Si la diferencia crece, el indexador está atrasado; si la diferencia es cero pero el saldo difiere, comprueba si estás leyendo el saldo de un contrato de token frente al saldo nativo, y si la dirección tiene el checksum correcto.
La difusión devuelve nonce too low o replacement transaction underpriced. Ya se minó otra transacción con el mismo nonce o está pendiente. Consulta eth_getTransactionCount con pending y, si pretendes reemplazarla, sube la comisión hasta el umbral de reemplazo que exija tu nodo.
El recibo nunca aparece. Puede que la transacción no se haya propagado. Vuelve a difundir los mismos bytes en bruto a un segundo endpoint o consulta un explorador de bloques. No firmes una nueva transacción con el mismo nonce a menos que pretendas reemplazar la primera.
Errores 429 o de límite de tasa bajo carga. Los endpoints públicos compartidos aplican limitación de forma agresiva. Mueve las rutas de lectura intensiva a una API de datos indexados y reserva la capacidad RPC para las escrituras. Para un rendimiento sostenido, un nodo dedicado elimina los efectos de vecinos ruidosos.
Limitaciones y compromisos de cada capa
Las API de datos indexados son rápidas y cómodas, pero con consistencia eventual, y su cobertura de cadenas, tokens y protocolos DeFi varía. También concentran tu dependencia: una caída del indexador deja en blanco tu pantalla de cartera aunque la cadena esté sana. Mitígalo con una lectura RPC de respaldo para saldos nativos y una respuesta en caché del último estado bueno conocido.
Los endpoints RPC son autoritativos pero costosos de consultar para vistas de cartera, y las consultas de archivo para saldos históricos pueden ser lentas o no estar disponibles en nodos que no son de archivo. Firmar localmente te da la historia de custodia más sólida, pero pone la gestión de claves, la gestión de nonces y la estimación de comisiones en tu equipo. El monedero como servicio traslada esa carga, pero cambia quién tiene las claves y qué puedes demostrar a los auditores.
No hay una única división correcta. Una aplicación de consumo con muchas lecturas de bajo valor debería apoyarse en datos indexados. Una integración de tesorería o de exchange debería tratar el recibo RPC como fuente de verdad y usar el indexador solo para mostrar.
Próximos pasos para una integración de monedero en producción
Empieza por dejar escritos tu modelo de custodia y tu objetivo de frescura. Luego monta una cadena de extremo a extremo: lectura indexada, lectura RPC, firma local, difusión, recibo. Mide esa ruta con la tabla anterior antes de añadir una segunda cadena. El soporte multichain multiplica cada modo de fallo, así que demuestra primero la ruta de una sola cadena.
Cuando estés listo para elegir endpoints RPC, usa el Asistente RPC para obtener una recomendación concreta por red en lugar de copiar un endpoint de un artículo. Revisa el directorio de redes de OnFinality para confirmar la cobertura de cadenas y testnets, compara planes en la página de precios de RPC y considera un nodo dedicado si tu ruta de escritura necesita latencia predecible. Para equipos que construyen infraestructura Web3 más amplia, la descripción general del servicio de API explica cómo encaja el RPC gestionado junto a tus propios servicios.
- Documenta la ruta de lectura y la ruta de escritura por separado en tu runbook.
- Añade un indicador de antigüedad a cualquier saldo procedente de un indexador.
- Configura alertas sobre el retraso del indexador y la latencia de recibos, no solo sobre errores HTTP.
- Vuelve a ejecutar el procedimiento de medición tras cualquier cambio de proveedor o de plan.