Stackfy

Documentación de la API

Crea cobros en cripto directamente desde tu sistema y libera el acceso del cliente automáticamente cuando se confirme el pago.

Cómo funciona

El flujo típico de una integración (suscripción, hosting, streaming):

1. Tu sistema crea un cobro vía API  →  POST https://api.stackfy.io/v1/invoices
2. Llevas al cliente al pago  →  enlace de checkout O QR transparente
3. El cliente paga en cripto
4. Stackfy llama a tu webhook  →  POST a tu notification_url
5. Confirmas el cobro vía API  →  GET https://api.stackfy.io/v1/invoices/{id}
6. Status "complete"  →  liberas/renuevas el acceso del cliente

Recurrencia: cripto no tiene débito automático — en cada ciclo, tu sistema repite el paso 1.

Datos de tu cuenta

Dirección de la APIhttps://api.stackfy.io/v1
Tu store_idSEU_STORE_ID
Moneda predeterminadaBRL

Autenticación

Crea una clave en API e integración y envíala en la cabecera de cada llamada:

Authorization: Bearer SUA_CHAVE

La clave da acceso a tu cuenta — guárdala como una contraseña. Si se filtra, revócala al instante desde el panel.

Crear un cobro

POSThttps://api.stackfy.io/v1/invoices

CampoObligatorioDescripción
priceImporte (string), ej.: "49.90"
currencyMoneda del importe: BRL, USD, EUR… (o USDT para precio directo en dólar 1:1, solo con pay_currency=USDT)
store_idTu tienda: SEU_STORE_ID
pay_currencynoOmitido = multi-moneda (el comprador elige la cripto — ver abajo). Para FIJAR la red: BTC, USDT (Tron/TRC-20) o USDT-MATIC (Polygon). Fijar USDT requiere que la tienda tenga dirección en esa red. El price se mantiene en fiat.
notification_urlnoTu webhook (recibe el aviso de pago)
redirect_urlnoA dónde enviar al cliente tras pagar
metadatanoObjeto libre (ej.: tu id de pedido/usuario)

Multi-moneda — el comprador elige la cripto

Solo omite el campo pay_currency: Stackfy crea un pedido y el comprador elige entre BTC, USDT-Tron y USDT-Polygon en la pantalla de pago (las opciones dependen de lo que la tienda tenga habilitado). El price se mantiene en fiat; la conversión se hace al tipo de cambio del momento, cuando el comprador elige. La respuesta trae pay_currency: "ANY" y el checkout_url del selector.

curl -X POST https://api.stackfy.io/v1/invoices \
  -H "Authorization: Bearer SUA_CHAVE" \
  -H "Content-Type: application/json" \
  -d '{
    "price": "49.90",
    "currency": "BRL",
    "store_id": "SEU_STORE_ID"
  }'
# sin pay_currency = el comprador elige la cripto en el checkout

Ejemplo — cURL

curl -X POST https://api.stackfy.io/v1/invoices \
  -H "Authorization: Bearer SUA_CHAVE" \
  -H "Content-Type: application/json" \
  -d '{
    "price": "49.90",
    "currency": "BRL",
    "store_id": "SEU_STORE_ID",
    "notification_url": "https://seusite.com/webhooks/stackfy",
    "metadata": {"pedido": "1234", "usuario": "[email protected]"}
  }'

Ejemplo — Node.js

const r = await fetch("https://api.stackfy.io/v1/invoices", {
  method: "POST",
  headers: {
    "Authorization": "Bearer " + process.env.STACKFY_KEY,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    price: "49.90", currency: "BRL", store_id: "SEU_STORE_ID",
    notification_url: "https://seusite.com/webhooks/stackfy",
    metadata: { pedido: "1234" },
  }),
});
const invoice = await r.json();
// invoice.id  -> guárdalo en tu pedido
// redirige al cliente al checkout (ver abajo)

Ejemplo — PHP

$ch = curl_init("https://api.stackfy.io/v1/invoices");
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_POST => true,
  CURLOPT_HTTPHEADER => [
    "Authorization: Bearer " . getenv("STACKFY_KEY"),
    "Content-Type: application/json",
  ],
  CURLOPT_POSTFIELDS => json_encode([
    "price" => "49.90", "currency" => "BRL", "store_id" => "SEU_STORE_ID",
    "notification_url" => "https://seusite.com/webhooks/stackfy",
  ]),
]);
$invoice = json_decode(curl_exec($ch), true);

La respuesta es el cobro creado, con id, status ("pending") y los métodos de pago en payments (dirección, importe en cripto y URI para QR).

Llevar al cliente al pago

Opción A — Redirect (lo más simple)

Envía al cliente al checkout listo de Stackfy, usando el id del cobro:

https://pay.stackfy.io/c/<invoice_id>

El cliente ve el QR, paga y (si definiste redirect_url) vuelve a tu sitio.

Opción B — Transparente (en tu propio diseño)

Usa los datos de payments de la respuesta para montar tu propio QR/dirección:

{
  "id": "...",
  "status": "pending",
  "payments": [{
    "payment_address": "bc1q...",        // dirección de cobro
    "amount": "0.00071",                 // importe en cripto
    "currency": "BTC",
    "payment_url": "bitcoin:bc1q...?amount=0.00071"  // se vuelve QR
  }]
}

Webhook (confirmación de pago)

Cuando se paga el cobro, Stackfy hace un POST firmado a tu servidor. Verificas la firma con tu secreto y listo — no necesitas volver a consultar nada.

1. Configura

En API e integración, guarda la URL de tu servidor (recibe el aviso) y copia tu secreto de firma (whsec_…). No necesitas configurar notification_url: todo cobro creado por Stackfy (API https://api.stackfy.io/v1 o panel) ya apunta por sí solo a nuestro relay.

Stackfy recibe la confirmación, verifica el estado real del cobro internamente y solo entonces lo reenvía, ya firmado, a tu servidor.

2. Lo que llega a tu servidor

Cabecera X-Stackfy-Signature: t=<timestamp>,v1=<hmac_sha256> y cuerpo JSON:

{
  "id": "<invoice_id>",
  "status": "complete",
  "price": "49.90",
  "currency": "BRL",
  "paid_currency": "BTC",
  "metadata": { "pedido": "1234" },
  "store_id": "SEU_STORE_ID"
}

3. Valida la firma

La firma es HMAC-SHA256 del texto "<timestamp>.<corpo_cru>" usando tu secreto. Compara en tiempo constante. El mismo esquema que Stripe.

Node.js / Express

const crypto = require("crypto");
// usa el cuerpo CRUDO (raw), no el JSON ya parseado:
app.post("/webhooks/stackfy", express.raw({type:"*/*"}), (req, res) => {
  const raw = req.body.toString("utf8");
  const [t, v1] = req.headers["x-stackfy-signature"].split(",")
                    .map(p => p.split("=")[1]);
  const expected = crypto.createHmac("sha256", process.env.STACKFY_WHSEC)
                         .update(t + "." + raw).digest("hex");
  const ok = crypto.timingSafeEqual(Buffer.from(v1), Buffer.from(expected));
  if (!ok) return res.status(401).end();              // falsificado -> rechaza

  const ev = JSON.parse(raw);
  if (ev.status === "complete") liberar(ev.metadata.pedido);
  res.status(200).end();                               // responde 200 rápido
});

PHP

$raw = file_get_contents("php://input");
parse_str(str_replace(",", "&", $_SERVER["HTTP_X_STACKFY_SIGNATURE"]), $sig);
$expected = hash_hmac("sha256", $sig["t"] . "." . $raw, getenv("STACKFY_WHSEC"));
if (!hash_equals($expected, $sig["v1"])) { http_response_code(401); exit; }

$ev = json_decode($raw, true);
if ($ev["status"] === "complete") liberar_acesso($ev["metadata"]["pedido"]);
http_response_code(200);
Buenas prácticas: usa el cuerpo crudo (no vuelvas a serializar el JSON antes de validar); el webhook puede llegar más de una vez para el mismo cobro → trátalo de forma idempotente; libera el acceso en complete (o confirmed).

Alternativa: sin webhook (polling)

Si prefieres no exponer un endpoint, consulta el estado cuando quieras: GEThttps://api.stackfy.io/v1/invoices/<id> con tu clave. La verdad siempre está en la API.

Referencia de estados

statusSignificado¿Liberar acceso?
pendingEsperando pagoNo
paidVisto en la red, 0 confirmacionesTodavía no (puede revertirse)
confirmedConfirmado en la red (≥1 conf)
completePagado y liquidado
expiredTiempo agotado sin pagarNo
invalidPago inválidoNo

¿Dudas de integración? [email protected]

© 2026 Stackfy · stackfy.io · Crear cuenta gratis · Términos · Privacidad