# Numbay — documentación completa > Numbay es una plataforma de números telefónicos virtuales de EE. UU. para recibir y enviar SMS online: número permanente sin SIM, buzón web en tiempo real, recargas con QvaPay o USDT/USDC (BSC), y API REST pública con webhooks firmados. Sitio: https://numbay.io · Índice corto: https://numbay.io/llms.txt ## Cómo funciona 1. Crea una cuenta en https://numbay.io/signup (email/contraseña o Google). Cada cuenta tiene una wallet interna en centavos de USD. 2. Recarga saldo con QvaPay o cripto (USDT/USDC en la red BSC) desde el panel o por API. 3. Renta un número de EE. UU. del catálogo: se cobra la renta mensual de tu saldo y se renueva automáticamente cada 30 días mientras tengas fondos (con periodo de gracia antes de liberarlo). 4. Recibe SMS en el buzón web estilo chat (tiempo real) o intégrate por API/webhooks. El envío desde números de EE. UU. requiere registro 10DLC; hasta entonces el número es solo de recepción. Las llaves de API y los webhooks se gestionan en https://numbay.io/settings. ## API pública Base: `https://numbay.io/api/v1` · Autenticación: `Authorization: Bearer nb_live_...` (o header `x-api-key`). Las llaves se crean en Settings → API con scope de solo lectura (`read`) o lectura y escritura (`read`+`write`). Dinero siempre en **centavos enteros** (`amountCents`). Errores en JSON: `{ "error": "CODE", "message"? }`. Rate limit por llave: **120/min** lectura, **20/min** escritura → `429` con header `Retry-After`. ### GET /wallet (read) Saldo y últimos movimientos. Query: `ledger_limit` (1–100, default 20). ```json { "data": { "balanceCents": 5000, "currency": "USD", "ledger": [ { "id": "...", "amountCents": 1000, "type": "TOPUP", "refId": "...", "note": "...", "balanceAfter": 5000, "createdAt": "..." } ] } } ``` ### GET /numbers (read) Números del usuario. Query: `status` (`ACTIVE|SUSPENDED|RELEASED`). ### GET /numbers/available (read) Inventario rentable. Query: `country` (ej. `US`), `limit` (1–20, default 10). ### POST /numbers (write) Renta un número. **Compra inventario real: usa `Idempotency-Key` en los reintentos.** ``` POST /api/v1/numbers Idempotency-Key: { "country": "US", "e164": "+14155551008" } ``` `201 { "data": { "id", "e164" } }` · Errores: `400 INVALID_INPUT`, `402 INSUFFICIENT_BALANCE`, `403 KYC_REQUIRED`, `409 NO_INVENTORY`. ### GET /messages (read) Mensajes, más recientes primero. Query: `numberId`, `direction` (`INBOUND|OUTBOUND`), `since` (ISO 8601), `limit` (1–100), `cursor` (id devuelto en `nextCursor`). ```json { "data": [ { "id": "...", "numberId": "...", "conversationId": "...", "direction": "INBOUND", "from": "+1...", "to": "+1...", "body": "...", "segments": 1, "status": "RECEIVED", "costCents": 0, "createdAt": "..." } ], "nextCursor": "..." } ``` ### POST /topups (write) Inicia una recarga. Acepta `Idempotency-Key`. ``` { "gateway": "QVAPAY" | "TRONDEALER", "amountCents": 100..100000 } ``` `201 { "data": { "id", "gateway", "url"?, "address"?, "amountCents" } }` — QvaPay devuelve `url` de pago; TronDealer devuelve `address` (USDT/USDC en BSC). La acreditación llega por webhook interno/reconciliación: consulta el estado o suscríbete al evento `payment.completed`. ### GET /topups/{id} (read) `{ "data": { "id", "status": "PENDING|PAID|EXPIRED|FAILED", "gateway", "amountCents", "asset", "url"?, "address"?, "createdAt", "paidAt" } }` ## Webhooks salientes Configura endpoints en Settings → Webhooks (URL https pública). Eventos: - `message.received` — SMS entrante en uno de tus números. `data` = mismo formato que GET /messages. - `payment.completed` — recarga acreditada. `data` = `{ id, gateway, amountCents, asset, paidAt }`. Cuerpo de cada entrega: ```json { "id": "", "event": "message.received", "createdAt": "...", "data": { } } ``` ### Firma Headers: `x-numbay-event`, `x-numbay-timestamp` (epoch segundos), `x-numbay-signature`. La firma es HMAC-SHA256 en hex de `${timestamp}.${rawBody}` con el secreto del endpoint. Verificación (Node): ```js import { createHmac, timingSafeEqual } from "node:crypto"; function verify(req, rawBody, secret) { const ts = req.headers["x-numbay-timestamp"]; const expected = createHmac("sha256", secret).update(`${ts}.${rawBody}`).digest("hex"); const got = req.headers["x-numbay-signature"] ?? ""; return got.length === expected.length && timingSafeEqual(Buffer.from(got), Buffer.from(expected)) && Math.abs(Date.now() / 1000 - Number(ts)) < 300; // tolerancia 5 min } ``` ### Entrega y reintentos Responde 2xx en menos de 5 s (procesa async si necesitas más). Semántica **at-least-once**: deduplica por `id`. Reintentos con backoff: 1m, 5m, 15m, 1h, 4h, 12h, 24h (8 intentos en total) y luego `FAILED` definitivo. Desde el panel puedes ver las últimas entregas, reenviarlas manualmente y rotar el secreto.