API pública · v1 · Gratis
API de Swapnoir
Tasas de cambio en tiempo real, monedas admitidas y seguimiento de órdenes para tu billetera, bot o sitio web. Solo lectura, sin clave de API y sin cuenta.
- URL base
https://swapnoir.com/api/v1- Autenticación
- Ninguna
- Formato
- JSON, UTF-8
- Errores
- RFC 9457
Descripción general
La API de Swapnoir le da a tu app los mismos datos en tiempo real que usa la plataforma de intercambio de swapnoir.com. Es una pequeña API REST sobre HTTPS con tres endpoints, devuelve JSON y está descrita en un archivo OpenAPI 3.1 que puedes cargar en Postman, Insomnia, Scalar o un generador de código.
Muestra tasas en tiempo real
Widgets de precios, calculadoras y bots. Las estimaciones ya incluyen todas las comisiones del pago.
Envía usuarios a un intercambio
Abre desde tu app un intercambio ya preparado en swapnoir.com con un solo enlace.
Sigue órdenes
Sigue un intercambio por su ID de orden y avisa a tus usuarios cuando se complete.
Inicio rápido
No necesitas registrarte. Ejecuta estos comandos en una terminal; cada uno funciona por sí solo.
- Consulta lo que puedes intercambiar. Usa el
idde cada moneda en las demás llamadas.curl "https://swapnoir.com/api/v1/currencies" - Obtén una estimación en tiempo real. ¿Cuánto XMR obtienes con 0.01 BTC, después de comisiones?
curl "https://swapnoir.com/api/v1/estimate?from=BTC&to=XMR&amount=0.01" - Envía a tu usuario al intercambio y síguelo. El usuario termina en swapnoir.com y obtiene una página de la orden. Su ID te permite seguir la orden.
curl "https://swapnoir.com/api/v1/orders/K7M2QX9PRT4B"
Solicitudes y datos
| URL base | https://swapnoir.com/api/v1. Solo HTTPS. |
|---|---|
| Métodos | Todos los endpoints son GET. Los parámetros van en la cadena de consulta o en la ruta. |
| Respuestas | application/json, UTF-8. Los errores usan application/problem+json. |
| Cantidades | Cadenas decimales como "0.01", para no perder precisión. Envía las cantidades con punto y como máximo los decimals de la moneda. |
| ID de moneda | Moneda más red, por ejemplo BTC, USDT-TRC20. En las solicitudes no se distingue entre mayúsculas y minúsculas; en las respuestas, siempre en mayúsculas. |
| Fechas y horas | ISO 8601 en UTC, por ejemplo 2026-10-05T12:00:00.000Z. |
| Navegadores | CORS está abierto (Access-Control-Allow-Origin: *), así que puedes llamar a la API desde una página web. No se usan cookies. |
| Tor | También disponible a través de Tor en http://swapnoqyyp3mfh3hoypzmvpnau7gymt7c32tybx2qew3s7sw7bzz7aqd.onion/api/v1, con los mismos endpoints y límites. |
| Control de versiones | La versión va en la ruta. Dentro de v1 solo añadimos cosas: nuevos endpoints, nuevos parámetros opcionales, nuevos campos de respuesta y nuevas monedas, así que ignora los campos que no conozcas. Cualquier cambio que rompa una integración se publica como una versión nueva, y v1 sigue funcionando en paralelo. |
Autenticación
Ninguna. No hay claves de API, cuentas ni tokens, y las solicitudes no se vinculan a nadie. Nunca envíes credenciales, frases semilla ni claves privadas a la API; nunca te las pedirá.
Límites de solicitudes
Los límites se cuentan por conexión en una ventana móvil de un minuto.
| Endpoint | Solicitudes por minuto |
|---|---|
GET /currencies | 60 |
GET /estimate | 90 |
GET /orders/{id} | 30 |
Cada respuesta incluye las cabeceras estándar RateLimit-Policy (por ejemplo 90;w=60) y RateLimit (por ejemplo limit=90, remaining=89, reset=60). Si superas el límite, recibes un 429 con una cabecera Retry-After en segundos.
- Guarda
/currenciesen caché durante al menos 5 minutos; cambia muy poco. - Mientras el usuario escribe una cantidad, espera aproximadamente medio segundo tras la última pulsación antes de pedir una estimación.
- Consulta una orden como máximo cada 10 segundos y deja de hacerlo cuando
finalseatrue.
Errores
Los errores usan el formato estándar RFC 9457 problem details. Comprueba el estado HTTP y luego decide según code, que nunca cambia. detail es un mensaje sencillo en inglés que puedes mostrar a tu usuario, y type enlaza con la fila correspondiente de la tabla de abajo.
{
"type": "https://swapnoir.com/api#error-amount_too_small",
"title": "Amount below minimum",
"status": 422,
"detail": "The minimum for this pair is 0.00005799 BTC.",
"code": "amount_too_small",
"min_amount": "0.00005799"
}| Código | HTTP | Significado |
|---|---|---|
invalid_parameter | 400 | Falta un parámetro de consulta o tiene un formato incorrecto. param indica cuál. |
same_currency | 400 | from y to son la misma moneda. |
receive_not_supported | 400 | La moneda to es solo de envío (Lightning). |
amount_too_small | 422 | La cantidad está por debajo del mínimo para este par. min_amount contiene el mínimo. |
pair_not_supported | 422 | Este par de monedas y redes no se ofrece. |
pair_unavailable | 503 | Ahora mismo no hay ninguna tasa disponible para este par. Vuelve a intentarlo más tarde o prueba con otra cantidad. |
not_found | 404 | No hay ninguna orden con este ID, o la orden se ha eliminado. |
rate_limited | 429 | Has alcanzado el límite de solicitudes. Espera el número de segundos indicado en Retry-After. |
internal_error | 500 | Algo salió mal por nuestra parte. Vuelve a intentarlo más tarde. |
Referencia
Listar monedas
GET/api/v1/currencies
Todas las monedas y redes que admite Swapnoir. Un token en otra red es una moneda distinta, por ejemplo USDT-TRC20 y USDT-ERC20. La lista cambia muy poco; guárdala en caché unos minutos.
El ejemplo muestra tres de las monedas. Los campos de respuesta de abajo son por moneda.
Solicitud
curl "https://swapnoir.com/api/v1/currencies"const res = await fetch("https://swapnoir.com/api/v1/currencies");
const { currencies } = await res.json();
// Currencies a user can receive
const receivable = currencies.filter((c) => c.receive);import requests
r = requests.get("https://swapnoir.com/api/v1/currencies", timeout=10)
r.raise_for_status()
currencies = r.json()["currencies"]Respuesta
{
"currencies": [
{
"id": "BTC",
"ticker": "BTC",
"name": "Bitcoin",
"network": "Bitcoin",
"decimals": 8,
"send": true,
"receive": true,
"memo": null,
"icon_url": "https://swapnoir.com/assets/coins/btc.svg"
},
{
"id": "BTC-LN",
"ticker": "BTC",
"name": "Bitcoin",
"network": "Lightning",
"decimals": 8,
"send": true,
"receive": false,
"memo": null,
"icon_url": "https://swapnoir.com/assets/coins/btc.svg"
},
{
"id": "XRP",
"ticker": "XRP",
"name": "XRP",
"network": "XRP Ledger",
"decimals": 6,
"send": true,
"receive": true,
"memo": "Destination tag",
"icon_url": "https://swapnoir.com/assets/coins/xrp.svg"
}
]
}Campos de la respuesta
| Campo | Tipo | Descripción |
|---|---|---|
id | string | Moneda y red. |
ticker | string | |
name | string | |
network | string | |
decimals | integer | Número máximo de decimales admitidos en las cantidades. |
send | boolean | Se puede usar como from. |
receive | boolean | Se puede usar como to. |
memo | string or null | Nombre del campo adicional que algunas redes requieren junto con la dirección, como Destination tag; null cuando no se usa. |
icon_url | string |
Obtener una estimación
GET/api/v1/estimate
Cuánto to recibe el usuario por amount de from, con todas las comisiones de intercambio y de red del pago ya incluidas. Las estimaciones son en tiempo real y no se reservan: la cantidad final se fija al crear el intercambio (tasa fija) o al confirmarse el depósito (tasa flotante).
Parámetros
| Nombre | Ubicación | Descripción |
|---|---|---|
fromobligatorio | query | Moneda que envía el usuario. Ejemplo: BTC. |
toobligatorio | query | Moneda que recibe el usuario. BTC-LN es solo de envío. Ejemplo: XMR. |
amountobligatorio | query | Cantidad de from, como número decimal con punto y como máximo los decimals de la moneda. Ejemplo: 0.01. |
rate | query | float (predeterminado) sigue el mercado hasta que se confirma el depósito. fixed bloquea la cantidad al crear el intercambio. Uno de estos valores: float, fixed. Ejemplo: float. |
Solicitud
curl "https://swapnoir.com/api/v1/estimate?from=BTC&to=XMR&amount=0.01&rate=float"const params = new URLSearchParams({ from: "BTC", to: "XMR", amount: "0.01" });
const res = await fetch(`https://swapnoir.com/api/v1/estimate?${params}`);
const data = await res.json();
if (!res.ok) {
// RFC 9457 problem, e.g. data.code === "amount_too_small"
throw new Error(data.detail);
}
console.log(data.amount_to, data.to);import requests
r = requests.get(
"https://swapnoir.com/api/v1/estimate",
params={"from": "BTC", "to": "XMR", "amount": "0.01"},
timeout=10,
)
data = r.json()
if not r.ok:
raise RuntimeError(data["code"] + ": " + data["detail"])
print(data["amount_to"], data["to"])Respuesta
{
"from": "BTC",
"to": "XMR",
"rate_type": "float",
"amount_from": "0.01",
"amount_to": "1.57166029",
"rate": "157.166029",
"usd_value": "866.32",
"quoted_at": "2026-10-05T12:00:00.000Z"
}{
"type": "https://swapnoir.com/api#error-amount_too_small",
"title": "Amount below minimum",
"status": 422,
"detail": "The minimum for this pair is 0.00005799 BTC.",
"code": "amount_too_small",
"min_amount": "0.00005799"
}{
"type": "https://swapnoir.com/api#error-invalid_parameter",
"title": "Invalid parameter",
"status": 400,
"detail": "Unknown currency `DOG`. See /api/v1/currencies.",
"code": "invalid_parameter",
"param": "from"
}Campos de la respuesta
| Campo | Tipo | Descripción |
|---|---|---|
from | string | Moneda y red. |
to | string | Cualquier moneda, excepto las que son solo de envío. |
rate_type | string | Tipo de tasa |
amount_from | string | La cantidad que consultaste. |
amount_to | string | Lo que recibe el usuario, después de todas las comisiones. |
rate | string | Cantidad de to por cada 1 from, después de comisiones. |
usd_value | string or null | Valor aproximado en dólares estadounidenses de amount_from, cuando se conoce. |
quoted_at | string |
Obtener una orden
GET/api/v1/orders/{id}
Estado en tiempo real y detalles de un intercambio. El ID de orden es la última parte de la URL de la página de la orden. Cualquiera que tenga el ID puede ver la orden, así que trátalo como una contraseña. Consulta como máximo cada 10 segundos y deja de hacerlo cuando final sea true. Las órdenes se eliminan 7 días después de finalizar.
Parámetros
| Nombre | Ubicación | Descripción |
|---|---|---|
idobligatorio | path | ID de orden, por ejemplo K7M2QX9PRT4B. |
Solicitud
curl "https://swapnoir.com/api/v1/orders/K7M2QX9PRT4B"const res = await fetch(`https://swapnoir.com/api/v1/orders/${orderId}`);
if (res.status === 404) {
// wrong ID, or the order was deleted
}
const order = await res.json();
console.log(order.status, order.final);import time
import requests
while True:
r = requests.get(f"https://swapnoir.com/api/v1/orders/{order_id}", timeout=10)
if r.status_code == 404:
break # wrong ID, or the order was deleted
order = r.json()
print(order["status"])
if order["final"]:
break
time.sleep(15)Respuesta
{
"id": "K7M2QX9PRT4B",
"status": "confirming",
"final": false,
"rate_type": "float",
"created_at": "2026-10-05T12:00:00.000Z",
"updated_at": "2026-10-05T12:06:12.000Z",
"from": {
"currency": "BTC",
"amount": "0.01"
},
"to": {
"currency": "XMR",
"amount": "1.57166029",
"amount_is_final": false
},
"deposit": {
"address": "bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq",
"memo": null,
"expires_at": null
},
"payout": {
"address": "888tNkZrPN6JsEgekjMnABU4TBzc2Dt29EPAvkRxbANsAnjyPbb3iQ1YBRk1UXcdRsiKc9dhwMVgN5S9cQUiyoogDavup3H",
"memo": null
},
"refund": null,
"transactions": {
"deposit": {
"hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"url": "https://mempool.space/tx/e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"payout": null
},
"links": {
"order_page": "https://swapnoir.com/order/K7M2QX9PRT4B",
"receipt": "https://swapnoir.com/order/K7M2QX9PRT4B/receipt.txt"
}
}{
"type": "https://swapnoir.com/api#error-not_found",
"title": "Not found",
"status": 404,
"detail": "No order with this ID. Orders are deleted 7 days after they finish.",
"code": "not_found"
}Campos de la respuesta
| Campo | Tipo | Descripción |
|---|---|---|
id | string | ID de orden |
status | string | Estado de la orden |
final | boolean | Es true para done, expired, refunded y failed: deja de consultar. |
rate_type | string | Tipo de tasa |
created_at | string | |
updated_at | string | |
from | object | |
from.currency | string | Moneda y red. |
from.amount | string | Cantidad que hay que depositar. |
to | object | |
to.currency | string | Moneda y red. |
to.amount | string or null | Pago estimado, o el pago final cuando amount_is_final es true. |
to.amount_is_final | boolean | |
deposit | object | |
deposit.address | string or null | Dirección a la que el usuario envía el depósito; null mientras el estado es preparing. |
deposit.memo | string or null | Memo o etiqueta de destino que debe incluirse con el depósito, si se indica. |
deposit.expires_at | string or null | Enviar antes de este momento, si se indica. |
payout | object | |
payout.address | string | |
payout.memo | string or null | |
refund | null or object | |
refund.address | string | |
refund.memo | string or null | |
transactions | object | |
transactions.deposit | null or object | |
transactions.deposit.hash | string | |
transactions.deposit.url | string or null | Enlace al explorador de bloques, cuando se conoce. |
transactions.payout | null or object | |
transactions.payout.hash | string | |
transactions.payout.url | string or null | Enlace al explorador de bloques, cuando se conoce. |
links | object | |
links.order_page | string | |
links.receipt | string |
Guías
Crear un intercambio
Los intercambios se crean en swapnoir.com, así que tu usuario siempre obtiene su propia página de la orden y mantiene el control sobre ella. Tu app envía al usuario allí con las monedas y la cantidad ya indicadas:
| Enlace | Qué abre |
|---|---|
https://swapnoir.com/exchange?from=BTC&to=XMR&amount=0.01&rate=float | El intercambio en el paso de la dirección, con la estimación en tiempo real visible. Ideal para botones «Intercambiar ya». |
https://swapnoir.com/?from=BTC&to=XMR&amount=0.01 | La página de inicio con el cuadro de intercambio ya completado, para que el usuario aún pueda cambiar las monedas y la cantidad. |
Ambos aceptan los mismos from, to, amount y rate opcional que Obtener una estimación. Para abrir la página en otro idioma, pon primero el código de idioma, por ejemplo /de/exchange?….
<a href="https://swapnoir.com/exchange?from=BTC&to=XMR&amount=0.01&rate=float" rel="noopener">
Exchange BTC to XMR on Swapnoir
</a>- El usuario pega su dirección de recepción y, si quiere, una dirección de reembolso, supera una breve verificación de seguridad y pulsa Intercambiar ya.
- Llega a la página de su orden,
https://swapnoir.com/order/<ID>, con la dirección de depósito y la cantidad. - Si tu app debe seguir la orden, pide al usuario que pegue el enlace o el ID de la orden y luego consulta periódicamente Obtener una orden.
Estados de la orden
Un intercambio normal pasa por awaiting → confirming → exchanging → sending → done. Muestra status a tu usuario con tus propias palabras y deja de consultar cuando final sea true.
| Estado | Final | Significado |
|---|---|---|
preparing | No | Se está preparando la dirección de depósito. Suele aparecer en pocos minutos. |
awaiting | No | Esperando el depósito. Envía solo mientras la orden esté en este estado y antes de deposit.expires_at. |
confirming | No | Se detectó el depósito y está a la espera de confirmaciones de la red. |
exchanging | No | El depósito está confirmado y se está intercambiando. |
sending | No | Las monedas intercambiadas se están enviando a la dirección de recepción. |
processing | No | En curso. Se usa cuando no se conoce un estado más concreto. |
done | Sí | Completado. Se envió el pago; consulta transactions.payout. |
expired | Sí | No llegó ningún depósito a tiempo. Un depósito tardío aún puede completarse o reembolsarse a través de soporte. |
hold | No | En pausa para una revisión rutinaria. El usuario debe contactar con soporte e indicar el ID de orden. |
attention | No | Hay algo que revisar, por ejemplo un depósito con una cantidad incorrecta. El usuario debe contactar con soporte. |
refunding | No | El depósito se está devolviendo a la dirección de reembolso. |
refunded | Sí | El depósito se devolvió. |
failed | Sí | No se pudo completar el intercambio. El usuario debe contactar con soporte. |
Monedas admitidas
La misma lista que devuelve Listar monedas. Con el tiempo se añaden monedas nuevas, así que lee la lista desde la API en lugar de escribirla en el código.
| ID | Moneda | Red | Decimales | Recibir | Memo |
|---|---|---|---|---|---|
BTC | Bitcoin | 8 | Sí | – | |
XMR | Monero | 12 | Sí | – | |
ETH | Ethereum | 8 | Sí | – | |
USDT-TRC20 | Tron (TRC20) | 6 | Sí | – | |
USDT-ERC20 | Ethereum (ERC20) | 6 | Sí | – | |
USDT-SOL | Solana | 6 | Sí | – | |
USDC-ERC20 | Ethereum (ERC20) | 6 | Sí | – | |
LTC | Litecoin | 8 | Sí | – | |
SOL | Solana | 9 | Sí | – | |
BTC-LN | Lightning | 8 | Solo envío | – | |
TRX | Tron | 6 | Sí | – | |
BNB | BNB Smart Chain (BEP20) | 8 | Sí | – | |
DOGE | Dogecoin | 8 | Sí | – | |
ZEC | Zcash | 8 | Sí | – | |
BCH | Bitcoin Cash | 8 | Sí | – | |
DASH | Dash | 8 | Sí | – | |
XRP | XRP Ledger | 6 | Sí | Etiqueta de destino |
Lista de comprobación para la integración
- Muestra la redMuestra siempre la red junto a la moneda, p. ej., USDT en Tron. Un envío por la red equivocada puede suponer la pérdida de los fondos.
- Muestra el memoCuando
deposit.memotiene valor, el depósito debe incluirlo. Muéstralo con la misma claridad que la dirección. - Explica la tasa fijaUn intercambio con tasa fija paga la cantidad cotizada solo si el usuario envía exactamente
from.amountantes dedeposit.expires_at. - Mantén privados los ID de ordenCualquiera que tenga un ID puede ver esa orden. No incluyas los ID en analíticas, registros ni URL públicas.
- Gestiona los errores por códigoDecide según
code, muestradetaily respetaRetry-After. - Enlaza al sitio auténticoEnlaza solo a https://swapnoir.com. Nunca pidas a los usuarios frases semilla ni claves privadas.
Registro de cambios
- v1 publicada.
GET /currencies,GET /estimate,GET /orders/{id}, errores RFC 9457, cabecerasRateLimity la descripción OpenAPI 3.1.
Soporte
Preguntas, ideas o límites más altos para tu integración: envíanos un mensaje o escríbenos a info@swapnoir.com. El uso de la API se rige por nuestras páginas de Términos y Privacidad.
Última actualización: .