kemBusiness
PlataformaProductoCómo funcionaNóminasPreciosDesarrolladoresPreguntas frecuentes
Iniciar sesiónEmpezar↗

Documentación para desarrolladores

Todo lo necesario para cobrar pagos en USDT con la API de Kem Business: autenticación, los endpoints de pagos y webhooks firmados que dirigen el estado de tus pedidos.

AutenticaciónPagosErrores y límitesWebhooksPruebas

Autenticación

Crea claves API en el panel, en «Claves API», y envía la clave secreta como Bearer token en cada petición. Las claves de prueba (sk_test_…) crean pagos de prueba; las claves live (sk_live_…) mueven dinero real.

Authorization: Bearer sk_live_...   # or sk_test_...
Base URL: https://api-business.kemapp.io

Pagos

Crea un pago y envía a tu cliente a su checkout_url alojada: Kem se encarga de billeteras, redes y confirmaciones. Sigue el estado consultando el pago o, mejor, con webhooks.

POST/v1/payments
curl -X POST https://api-business.kemapp.io/v1/payments \
  -H "Authorization: Bearer sk_test_..." \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: order-1042" \
  -d '{
    "amount": "25.000000",
    "currency": "USDT",
    "merchant_reference": "order-1042",
    "customer_email": "[email protected]",
    "description": "Pro plan",
    "return_url": "https://yourshop.example/thanks",
    "metadata": {"order_id": "1042"}
  }'
{
  "id": "pay_01J...",
  "status": "pending",
  "mode": "test",
  "amount": "25.000000",
  "amount_minor": 25000000,
  "amount_refunded_minor": 0,
  "fee_bps": null,
  "fee_minor": null,
  "net_minor": null,
  "currency": "USDT",
  "network": null,
  "merchant_reference": "order-1042",
  "checkout_url": "https://pay.kemapp.io/pay_01J...",
  "checkout_expires_at": "2026-07-13T13:30:00+00:00",
  "transaction_id": null,
  "detected_at": null,
  "confirmation_pending": false,
  "created_at": "2026-07-13T13:00:00+00:00",
  "updated_at": "2026-07-13T13:00:00+00:00"
}

Idempotency-Key — opcional pero recomendado: un reintento con la misma clave devuelve el pago original en lugar de crear un duplicado.

GET/v1/payments— query: status, limit (1–100, default 20), cursor · returns has_more, next_cursor
GET/v1/payments/{id}

amount — decimal string with 6 places ("25.000000"); amount_minor — the same value as an integer in micro-USDT.

fee_minor and net_minor are null while a payment is in flight and are frozen when it succeeds. Reconcile your payout against net_minor, not amount_minor — the difference is our fee (fee_bps).

Ciclo de vida del pago

pending → detected → succeeded · failed · expired

pending — esperando la transferencia · detected — vista en cadena, confirmando · succeeded — fondos confirmados en tu billetera (entrega con este evento) · failed / expired — terminales. Los reembolsos llegan como eventos de webhook.

checkout window: 30 minutes, then → expired

Errores y límites

Todos los errores usan un mismo sobre. Los códigos son estables: bifurca por error.code, nunca por el mensaje.

HTTP 4xx/5xx
{
  "error": {
    "code": "idempotency_conflict",
    "message": "Idempotency-Key reused with a different request"
  }
}
401 unauthorizedmissing or invalid API key
404 payment_not_foundunknown payment id (or a live id with a test key)
409 idempotency_conflictIdempotency-Key reused with a different body — identical retries replay the original response
422 validation_errormalformed body — bad amount, unsupported currency. message reads “{field}: {reason}”
429 rate_limitedover the per-key budget: 100 writes/min, 1000 reads/min

Productos, enlaces de pago, endpoints de webhooks y reembolsos se gestionan desde el panel; aún no tienen endpoints REST públicos.

Webhooks

Añade un endpoint en el panel, en «Webhooks», y elige los eventos que te interesan. Cada endpoint recibe su propio secreto de firma whsec_…, mostrado una sola vez al crearlo.

payment.createdA payment intent was created (API or checkout link).
payment.detectedThe transfer was seen on-chain / in the KEM ledger; confirming.
payment.succeededFunds are confirmed in your business wallet. Fulfill on this event.
payment.failedThe payment failed.
payment.expiredThe checkout window closed without payment.
payment.confirmation_delayedThe customer paid, but it couldn't be confirmed inside the checkout window. Don't treat this as expired — hold the order.
payment.refund.createdA refund was initiated from the dashboard.
payment.refund.succeededThe refund settled back to the customer.

Cuerpo del evento

{
  "id": "payment_event_01J...",
  "type": "payment.succeeded",
  "created": "2026-07-13T13:04:12+00:00",
  "data": {
    "payment": {
      "id": "pay_01J...",
      "status": "succeeded",
      "amount_minor": 25000000,
      "currency": "USDT",
      "merchant_reference": "order-1042",
      "network": "TRON",
      "product_id": null,
      "payment_link_id": null
    }
  }
}

Verificación de firmas

Cada entrega lleva una cabecera Kem-Signature. Recalcula el HMAC sobre «<t>.» más el cuerpo crudo con tu secreto y compara en tiempo constante. Rechaza lo que no coincida.

Kem-Signature: t=<unix_timestamp>,v1=<hmac_sha256_hex>

signed_input = "<t>." + raw_request_body
v1 = HMAC_SHA256(endpoint_secret, signed_input)   # secret: whsec_...

# reject replays: drop the delivery when |now - t| > 300s
import crypto from "node:crypto";

export function verifyKemSignature(rawBody, header, secret) {
  // header: "t=1720000000,v1=hex"
  const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")));
  const expected = crypto
    .createHmac("sha256", secret)               // secret: whsec_...
    .update(`${parts.t}.`)
    .update(rawBody)                            // the RAW request bytes
    .digest("hex");
  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1));
}
import hashlib, hmac

def verify_kem_signature(raw_body: bytes, header: str, secret: str) -> bool:
    parts = dict(p.split("=") for p in header.split(","))
    expected = hmac.new(
        secret.encode(), f"{parts['t']}.".encode() + raw_body, hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(expected, parts["v1"])

Entrega y reintentos

Responde 2xx rápido. Las entregas fallidas se reintentan con backoff y luego pasan a dead-letter:

1m · 5m · 30m · 2h · 12h · 24h

Pruebas

Con una clave de prueba puedes llevar un pago por todo su ciclo sin mover dinero: simula transiciones y observa tus webhooks dispararse:

curl -X POST https://api-business.kemapp.io/v1/payments/{id}/_simulate/succeeded \
  -H "Authorization: Bearer sk_test_..."
BUILT IN THE GULF · SETTLED IN USDT ·
kemBusiness

Cobra
en stablecoins.

Abre el panel y recibe hoy tu primer pago en USDT, o repásalo con nosotros en una llamada de 20 minutos.

Abrir el panel↗Agenda una llamada↗

¿Ya usas kem? Iniciar sesión

Producto

  • Iniciar sesión
  • Crear cuenta
  • Agenda una demo

Kem para todos

  • App para consumidores
  • iOS — App Store
  • Android — Google Play

Empresa

  • Inversión de Tether
  • Política de privacidad
  • Términos y condiciones

Kem es un ecosistema de servicios cripto que da a las personas de todo el mundo acceso a la libertad financiera.

© 2026 Kem · El contenido de este sitio web, incluidos todos los datos, materiales y documentos disponibles a través de él, es confidencial y propiedad de KEM TECHNOLOGIES HOLDING Ltd, registrada en el Abu Dhabi Global Market (número de sociedad 000008598). Queda estrictamente prohibido cualquier uso, divulgación, distribución o reproducción no autorizados de este contenido, total o parcialmente, sin el consentimiento previo por escrito de KEM TECHNOLOGIES HOLDING Ltd. [email protected]

Hecho en el Golfo.