Saltar al contenido
Crypto Merchant

Desarrolladores

Billeteras fijas

Da a cada uno de tus clientes sus propias direcciones de depósito, que nunca cambian, una por red. Cada depósito se suma a tu saldo de Crypto Merchant, y tu servidor recibe un aviso de qué cliente lo envió, para que recargues la cuenta correcta.

Cómo obtener billeteras fijas

Elige billeteras de clientes al registrarte, o pide a soporte que active las billeteras fijas en una cuenta que ya tengas. Hasta que estén activadas, estos endpoints responden 403 sticky_wallets_unavailable. Usan la misma URL base, las mismas claves secretas y el mismo formato de errores que el resto de la API.

Antes de empezar

  1. 1

    Termina la configuración y elige tus monedas. Cada cliente recibe una dirección en las redes de las monedas que aceptas (portal, Configuración).

  2. 2

    Crea una clave secreta. En el portal, abre Desarrolladores y crea una clave de API. Se muestra una sola vez: guárdala en tu servidor, por ejemplo como CM_SECRET_KEY, y nunca en una página web ni en una app.

  3. 3

    Agrega un endpoint de webhook. También en Desarrolladores, agrega tu URL con los eventos deposit.pending, deposit.confirmed y deposit.dropped (o todos los eventos). Guarda su secreto de firma, whsec_…, para verificar cada solicitud.

Cómo funciona

  1. 1

    Un cliente abre la página de depósito de tu sitio.

  2. 2

    Tu servidor llama a POST /sticky-wallets con tu propio ID para ese cliente. La primera llamada crea las direcciones; cada llamada posterior devuelve las mismas.

  3. 3

    Muestras la dirección, con un código QR, de la moneda que elija el cliente.

  4. 4

    Cuando llegan las monedas, recibes deposit.pending y luego deposit.confirmed cuando la red las confirma.

  5. 5

    Con deposit.confirmed, acreditas el saldo al cliente indicado en sticky_wallet.reference.

Obtener la billetera de un cliente

POST/sticky-wallets

Crea la billetera del cliente en la primera llamada y devuelve la misma en cada llamada posterior: 201 cuando se acaba de crear y 200 después. Puedes llamarlo sin problema cada vez que se abre la página de depósito.

Parámetros del cuerpo

referenceObligatoriostring
Tu ID para este cliente: de 1 a 120 letras, números o . _ : @ + -, que empiece con una letra o un número. Una billetera por referencia, para siempre.
labelOpcionalstring
Un nombre que verás en el portal. Si lo vuelves a enviar, se reemplaza.
metadataOpcionalobject
Un objeto propio, de hasta 4 KB. Si lo vuelves a enviar, se reemplaza.
curl
curl https://cryptomerchant.online/api/v1/sticky-wallets \
  -H "Authorization: Bearer $CM_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "reference": "user-1042",
    "label": "Jane Doe",
    "metadata": { "plan": "pro" }
  }'
Node.js
// On your server, when a customer opens their deposit page
export async function depositAddresses(userId) {
  const res = await fetch("https://cryptomerchant.online/api/v1/sticky-wallets", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.CM_SECRET_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ reference: String(userId) }),
  });
  if (!res.ok) {
    const { error } = await res.json();
    throw new Error(`${error.code}: ${error.message}`);
  }
  const wallet = await res.json();
  return wallet.addresses; // [{ network, address, coins: [...] }, …]
}

El objeto billetera fija

idstring
El ID de la billetera, que empieza con sw_.
referencestring
Tu ID para el cliente.
addressesarray
Una entrada por red: network (tron, evm, sol, btc o ltc), la address y las coins que acepta. La dirección evm es la misma en Ethereum, BNB Smart Chain, Polygon, Base y Arbitrum.
pending_networksarray
Redes cuya dirección todavía se está preparando, algo poco frecuente. Vuelve a llamar en unos minutos y aparecerán en addresses.
created_atstring
Cuándo se creó la billetera.
sticky_wallet
{
  "id": "sw_8Kd2pQx7Vb1mNc3T",
  "object": "sticky_wallet",
  "reference": "user-1042",
  "label": "Jane Doe",
  "metadata": { "plan": "pro" },
  "addresses": [
    {
      "network": "tron",
      "address": "TXbajeGHq4Vb…",
      "coins": [
        { "id": "TRX.TRON", "symbol": "TRX", "network": "Tron" },
        { "id": "USDT.TRON", "symbol": "USDT", "network": "Tron" }
      ]
    },
    {
      "network": "evm",
      "address": "0xE550EC6d…",
      "coins": [
        { "id": "ETH.ETH", "symbol": "ETH", "network": "Ethereum" },
        { "id": "BNB.BSC", "symbol": "BNB", "network": "BNB Smart Chain" },
        { "id": "USDT.BSC", "symbol": "USDT", "network": "BNB Smart Chain" }
      ]
    }
  ],
  "pending_networks": [],
  "created_at": "2026-10-29T18:20:41.000Z"
}

Indica a tus clientes qué enviar

Muestra cada dirección junto con las monedas indicadas para ella. Las monedas de otra red, o los tokens que no aparecen en la lista, no se acreditan automáticamente: contacta a soporte si un cliente envía alguno.

Buscar billeteras

GET/sticky-wallets

GET/sticky-wallets/{id}

Busca una billetera por tu referencia, obtén una por su ID o recorre todas, de la más reciente a la más antigua: limit de 1 a 100, starting_after con el ID de la última billetera que tienes, y has_more indica si hay más.

curl
# By your reference
curl "https://cryptomerchant.online/api/v1/sticky-wallets?reference=user-1042" \
  -H "Authorization: Bearer $CM_SECRET_KEY"

# By id
curl https://cryptomerchant.online/api/v1/sticky-wallets/sw_8Kd2pQx7Vb1mNc3T \
  -H "Authorization: Bearer $CM_SECRET_KEY"

# All of them, 50 at a time
curl "https://cryptomerchant.online/api/v1/sticky-wallets?limit=50&starting_after=sw_8Kd2pQx7Vb1mNc3T" \
  -H "Authorization: Bearer $CM_SECRET_KEY"
Respuesta
{
  "object": "list",
  "data": [ { "id": "sw_8Kd2pQx7Vb1mNc3T", "object": "sticky_wallet", … } ],
  "has_more": false
}

Listar depósitos

GET/deposits

Todos los depósitos en las billeteras de tus clientes, del más reciente al más antiguo. Filtra por sticky_wallet (un ID de billetera) y status (pending, confirmed o dropped), y pagina con limit y starting_after (un ID de depósito). Úsalo para ponerte al día cuando tu servidor no recibió algunos webhooks.

curl
curl "https://cryptomerchant.online/api/v1/deposits?sticky_wallet=sw_8Kd2pQx7Vb1mNc3T&status=confirmed&limit=20" \
  -H "Authorization: Bearer $CM_SECRET_KEY"

El objeto depósito

idstring
El ID del depósito. Úsalo para acreditar cada depósito una sola vez.
statusstring
pending: detectado en la red, esperando confirmaciones. confirmed: definitivo y sumado a tu saldo. dropped: nunca se confirmó.
sticky_walletobject
La billetera a la que se envió: id y tu reference.
coinobject
La moneda y su red.
amountstring
Lo que envió el cliente, en la moneda.
feestring
La comisión, en la moneda.
net_amountstring
Lo que se sumó a tu saldo (monto menos comisión), una vez confirmado.
amount_usdstring
Su valor en dólares estadounidenses al momento de llegar.
tx_hashstring
El hash de la transacción; explorer_url la abre en un explorador de bloques.
deposit
{
  "id": "cmvu1x9a0000l10u8k2f3h7q",
  "object": "deposit",
  "status": "confirmed",
  "sticky_wallet": { "id": "sw_8Kd2pQx7Vb1mNc3T", "reference": "user-1042" },
  "coin": { "id": "USDT.TRON", "symbol": "USDT", "network": "Tron" },
  "address": "TXbajeGHq4Vb…",
  "amount": "250",
  "amount_usd": "250.00",
  "fee": "2.5",
  "net_amount": "247.5",
  "from_address": "TQn9Y2khEsLJ…",
  "tx_hash": "36423ec5…f00d4a",
  "explorer_url": "https://tronscan.org/#/transaction/36423ec5…f00d4a",
  "confirmations": 19,
  "detected_at": "2026-10-29T18:31:02.000Z",
  "confirmed_at": "2026-10-29T18:32:01.000Z"
}

Webhooks

Los eventos de depósito llevan el objeto depósito en data. Verifica la firma, como se explica en Webhooks, antes de confiar en uno.

deposit.pending
Se detectó en la blockchain un depósito en la billetera fija de uno de tus clientes y está esperando confirmaciones.
deposit.confirmed
Se confirmó un depósito en una billetera fija y se sumó a tu saldo, descontando la comisión: acredítaselo ahora a ese cliente.
deposit.dropped
Un depósito detectado en una billetera fija nunca se confirmó (falló o se eliminó de la blockchain).
server.js · acreditar al cliente
import express from "express";
import { verifyWebhook } from "./verify-webhook.js"; // from the Webhooks page
import { db } from "./db.js"; // your database; table webhook_events as on the Webhooks page

const app = express();

app.post(
  "/webhooks/crypto-merchant",
  express.raw({ type: "application/json" }),
  async (req, res) => {
    let event;
    try {
      event = verifyWebhook(req.body, req.get("CM-Signature"), process.env.CM_WEBHOOK_SECRET);
    } catch {
      return res.sendStatus(400);
    }
    try {
      // Save first: a repeat delivery has the same event.id and is ignored
      await db.query(
        "INSERT INTO webhook_events (id, type, payload) VALUES ($1, $2, $3) ON CONFLICT (id) DO NOTHING",
        [event.id, event.type, event],
      );
    } catch {
      return res.sendStatus(500); // not saved: we send it again later
    }
    res.sendStatus(200); // stored, so confirm it
    processEvents().catch(console.error); // or run it from a background job
  },
);

async function processEvents() {
  const { rows } = await db.query(
    "SELECT payload FROM webhook_events WHERE processed_at IS NULL ORDER BY received_at",
  );
  for (const { payload: event } of rows) {
    const deposit = event.data;
    if (event.type === "deposit.pending") {
      // Optional: show "deposit on its way" to deposit.sticky_wallet.reference
    }
    if (event.type === "deposit.confirmed") {
      // Credit once: creditCustomer must skip a deposit.id it has already credited
      await creditCustomer({
        customerId: deposit.sticky_wallet.reference,
        depositId: deposit.id,
        coin: deposit.coin.id, // e.g. "USDT.TRON"
        amount: deposit.net_amount, // or deposit.amount to cover the fee yourself
        txHash: deposit.tx_hash,
      });
    }
    await db.query("UPDATE webhook_events SET processed_at = now() WHERE id = $1", [event.id]);
  }
}

Errores

400
invalid_request: falta un campo o es incorrecto; el mensaje indica cuál.
401
unauthorized: la clave secreta falta o no es válida.
403
sticky_wallets_unavailable: las billeteras fijas no están activadas para este negocio, o su configuración no está terminada.
404
not_found: no hay ninguna billetera fija con ese ID.

Buenas prácticas

  • Acredita a un cliente solo con deposit.confirmed, y solo una vez por id de depósito: un webhook puede llegar más de una vez.
  • Decide quién paga la comisión: acredita net_amount para trasladarla al cliente, o amount para asumirla tú.
  • Tu referencia es la clave: volver a llamar a POST /sticky-wallets siempre es seguro, así que no necesitas guardar las direcciones.
  • Guarda la clave secreta en tu servidor. Si se filtra, revócala en Desarrolladores y crea una nueva.
  • Si tu endpoint estuvo caído, lista los depósitos confirmed y acredita los que todavía no procesaste.
  • ¿Vas a crear un saldo para tus clientes? Consulta cómo añadir recargas en cripto a las cuentas de clientes.