Manual de Integración CriptoFacil
Guía completa para integrar pagos en criptomonedas con ambientes Sandbox y Producción
Inicio Rápido
Integra CriptoFacil en 3 pasos simples:
Obtén Credenciales
Contacta a martin@criptofacil.cl para recibir tus credenciales de Sandbox o Producción
- API Key (sk_test_ o sk_live_)
- Merchant ID
- USDT de prueba (Sandbox)
Crea un Pago
Envía un POST al endpoint de creación de pagos con el monto y datos del cliente
POST /api/v1/payments/intentRecibe Webhooks
Configura tu webhook para recibir notificaciones cuando el pago se confirme
- payment.confirmed
- payment.failed
- payment.expired
Endpoints de API
Todos los endpoints disponibles para integrar pagos con CriptoFacil
/api/v1/payments/intentCrear Payment Intent
Crea una intención de pago y obtiene una URL de pago para redirigir al cliente
Sandbox:
https://criptofacil-qa-vercel.vercel.app/api/v1/payments/intentProducción:
https://cryptopay-production-6074.up.railway.app/api/v1/payments/intent/api/v1/payments/:payment_idConsultar Estado de Pago
Obtiene el estado actual de un pago específico usando su payment_id
Sandbox:
https://criptofacil-qa-vercel.vercel.app/api/v1/payments/pay_test_123Producción:
https://cryptopay-production-6074.up.railway.app/api/v1/payments/pay_live_123Descripción General
CriptoFacil ofrece dos ambientes completamente separados para el desarrollo e implementación de tu integración de pagos:
Ambiente Sandbox
Para desarrollo, testing y pruebas sin riesgo financiero
- Tokens de prueba gratuitos
- Red Polygon Amoy Testnet
- Confirmación rápida (3 bloques)
- Monto mínimo: $100 CLP
Ambiente Producción
Para procesar pagos reales de clientes
- Dinero real (USDT)
- Red Polygon Mainnet
- Confirmación estándar (12 bloques)
- Monto mínimo: $1,000 CLP
Ambiente Sandbox
Configuración Sandbox
https://criptofacil-qa-vercel.vercel.appsk_test_...merchant_test_...Proceso de Integración Sandbox
Solicita Credenciales de Sandbox
Contacta a martin@criptofacil.cl para recibir tus credenciales de prueba (API Key y Merchant ID)
Recibe USDT de Prueba
CriptoFacil te proporcionará USDT en la red Amoy (testnet) para que puedas realizar pruebas sin costo. Solo solicítalo al mismo email
Configura tu Wallet
Instala MetaMask y agrega la red Polygon Amoy Testnet con Chain ID 80002. Obtén MATIC gratis en faucet.polygon.technology para pagar gas fees
Integra y Prueba
Usa los endpoints de Sandbox para crear pagos de prueba y verifica que recibes webhooks correctamente en tu sistema
Valida tu Integración
Prueba diferentes escenarios: pagos exitosos, cancelados, expirados. Asegúrate de manejar todos los estados correctamente
Ambiente Producción
Configuración Producción
https://cryptopay-production-6074.up.railway.appsk_live_...merchant_live_...Proceso de Integración Producción
Solicita Credenciales de Producción
Contacta a martin@criptofacil.cl con la información legal de tu empresa para recibir credenciales de producción
Configura tu Cuenta Bancaria
Proporciona los datos de tu cuenta bancaria para recibir las liquidaciones en CLP (transferencia en 24 horas hábiles)
Configura Polygon Mainnet
Actualiza tu wallet a Polygon Mainnet (Chain ID 137). Los pagos ahora serán con USDT real
Lanza y Monitorea
Comienza con transacciones pequeñas, verifica webhooks y liquidaciones. Monitorea continuamente el estado de tus pagos
Diferencias Clave Entre Ambientes
| Aspecto | Sandbox | Producción |
|---|---|---|
| Propósito | Testing y desarrollo | Pagos comerciales reales |
| Dinero | Tokens de prueba | Dinero real |
| API Key | sk_test_... | sk_live_... |
| Merchant ID | merchant_test_... | merchant_live_... |
| Chain ID | 80002 (Amoy) | 137 (Polygon) |
| USDT Contract | Mock USDT | USDT Real |
| Monto mínimo | $100 CLP | $1,000 CLP |
| Confirmaciones | 3 bloques | 12 bloques |
| Expiración | 30 minutos | 15 minutos |
| Gas fees | Gratis (testnet) | Costo real (~$0.01) |
| Liquidación | No aplica | 24h hábiles a cuenta bancaria |
Requests & Responses
Request de Creación de Pago
Este es el cuerpo principal del request para crear un pago. Asegúrate de usar los parámetros correctos para el ambiente elegido.
Headers Requeridos
Content-Type: application/json
Authorization: Bearer {API_KEY}Request Body Completo
{
"merchant_id": "merchant_test_20241016_abc123", // Sandbox
// "merchant_id": "merchant_live_20241016_xyz789", // Producción
"amount": 1000, // Mínimo 100 CLP (sandbox) / 1000 CLP (producción)
"currency": "CLP",
"order_id": "ORDER_123",
"external_order_reference": "SHOP_ORDER_456", // Opcional
"customer_info": {
"email": "cliente@email.com",
"name": "Juan Pérez",
"rut": "12345678-9", // Opcional
"phone": "+56912345678" // Opcional
},
"redirect_urls": {
"success": "https://tu-tienda.com/pago-exitoso",
"cancel": "https://tu-tienda.com/pago-cancelado",
"webhook": "https://tu-tienda.com/webhook/crypto-payments"
},
"metadata": {
"product_name": "Tour Patagonia 5 días",
"product_id": "SKU_TOUR_001",
"category": "turismo",
"custom_field": "valor_personalizado"
}
}Response de Creación de Pago (200 OK)
{
"success": true,
"data": {
"payment_id": "pay_test_20241016_abc123", // Sandbox / Producción
"payment_url": "https://criptofacil-qa-vercel.vercel.app/pay/pay_test_20241016_abc123", // Sandbox
// "payment_url": "https://cryptopay-production-6074.up.railway.app/pay/pay_live_20241016_xyz789", // Producción
"amount_clp": 1000,
"amount_usdt": 1.05, // Aproximado, basado en la tasa de cambio del momento
"exchange_rate": {
"rate": 952.38, // CLP por USDT
"source": "coingecko",
"timestamp": "2024-10-16T10:00:00Z"
},
"fees": {
"platform_fee_usdt": 0.00945, // 0.9% de 1.05 USDT
"iva_fee_usdt": 0.0018, // 19% de 0.00945 USDT
"net_amount_usdt": 1.03875 // Monto neto en USDT a recibir
},
"expires_at": "2024-10-16T10:15:00Z", // 15 minutos después
"status": "pending"
}
}Response de Consulta de Pago (200 OK)
{
"success": true,
"data": {
"payment_id": "pay_test_20241016_abc123",
"status": "confirmed", // O 'processing', 'failed', 'expired'
"amount_clp": 1000,
"amount_usdt": 1.05,
"net_amount_usdt": 1.03875,
"transaction_hash": "0x123abc...", // Hash de la transacción en Polygon
"confirmations": 12, // Número de confirmaciones en Polygon
"created_at": "2024-10-16T10:00:00Z",
"confirmed_at": "2024-10-16T10:10:00Z" // Solo si status es 'confirmed'
}
}Webhooks
CriptoFacil enviará una petición POST a tu webhook_url configurada en el request de creación de pago.
Evento: payment.confirmed
POST https://tu-tienda.com/webhook/crypto-payments
Content-Type: application/json
X-Signature: hmac_signature_aqui // Firma para validación
{
"event": "payment.confirmed",
"payment_id": "pay_test_20241016_abc123",
"order_id": "ORDER_123",
"external_order_reference": "SHOP_ORDER_456",
"status": "confirmed",
"amount_clp": 1000,
"amount_usdt": 1.05,
"net_amount_usdt": 1.03875,
"transaction_hash": "0x123abc...",
"created_at": "2024-10-16T10:00:00Z",
"confirmed_at": "2024-10-16T10:10:00Z",
"fees": {
"platform_fee_usdt": 0.00945,
"iva_fee_usdt": 0.0018
},
"metadata": {
"product_name": "Tour Patagonia 5 días",
"product_id": "SKU_TOUR_001"
}
}Verificación de Firma
Para asegurar que la petición proviene de CriptoFacil, valida el header `X-Signature` usando HMAC-SHA256 con tu `webhook_secret` (proporcionado al darte de alta).
expected_signature = HMAC_SHA256(webhook_secret, payload_string)Otros eventos
payment.processing: Transacción detectada en blockchain, esperando confirmaciones.payment.failed: La transacción de pago falló o no se pudo procesar.payment.expired: El `payment_intent` expiró antes de recibir el pago.
Ejemplos de Código
Integración de la creación de pagos en diferentes lenguajes de programación.
Node.js / Express
const axios = require('axios');
async function createPaymentIntent(amount, orderId, metadata = {}) {
const API_BASE_URL = process.env.NODE_ENV === 'production'
? 'https://cryptopay-production-6074.up.railway.app'
: 'https://criptofacil-qa-vercel.vercel.app';
const API_KEY = process.env.CRIPTOFACIL_API_KEY; // sk_test_... or sk_live_...
const MERCHANT_ID = process.env.MERCHANT_ID; // merchant_test_... or merchant_live_...
try {
const response = await axios.post(
`${API_BASE_URL}/api/v1/payments/intent`,
{
merchant_id: MERCHANT_ID,
amount: amount,
currency: 'CLP',
order_id: orderId,
external_order_reference: `SHOP_${orderId}`, // Opcional
redirect_urls: {
success: `${process.env.APP_URL}/checkout/success?orderId=${orderId}`,
cancel: `${process.env.APP_URL}/checkout/cancel?orderId=${orderId}`,
webhook: `${process.env.APP_URL}/api/webhooks/cripto`
},
metadata: {
product_name: 'Producto Ejemplo',
product_id: 'SKU_EXAMPLE',
...metadata // Permite pasar datos adicionales
}
},
{
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json'
}
}
);
return response.data.data; // Retorna toda la data, incluyendo payment_url
} catch (error) {
console.error('Error creating payment intent:', error.response?.data || error.message);
throw error;
}
}
// Ejemplo de uso:
// const paymentData = await createPaymentIntent(50000, 'ORDER_789', { product_name: 'Camiseta Deportiva' });
// console.log('Payment URL:', paymentData.payment_url);
Python / Flask
import requests
import os
def create_payment_intent(amount: int, order_id: str, metadata: dict = None):
api_base_url = os.environ.get('API_BASE_URL_CRYPTO') # e.g. https://cryptopay-production-6074.up.railway.app or https://criptofacil-qa-vercel.vercel.app
api_key = os.environ.get('CRIPTOFACIL_API_KEY') # sk_live_... or sk_test_...
merchant_id = os.environ.get('MERCHANT_ID') # merchant_live_... or merchant_test_...
app_url = os.environ.get('APP_URL') # e.g. https://tu-tienda.com
if not all([api_base_url, api_key, merchant_id, app_url]):
raise ValueError("Missing required environment variables for CryptoFacil integration.")
url = f"{api_base_url}/api/v1/payments/intent"
headers = {
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json"
}
payload = {
"merchant_id": merchant_id,
"amount": amount,
"currency": "CLP",
"order_id": order_id,
"external_order_reference": f"SHOP_{order_id}", # Optional
"redirect_urls": {
"success": f"{app_url}/checkout/success?orderId={order_id}",
"cancel": f"{app_url}/checkout/cancel?orderId={order_id}",
"webhook": f"{app_url}/api/webhooks/cripto"
},
"metadata": {
"product_name": "Producto Ejemplo",
"product_id": "SKU_EXAMPLE",
**(metadata if metadata else {})
}
}
try:
response = requests.post(url, json=payload, headers=headers)
response.raise_for_status() # Raise an exception for bad status codes
return response.json()["data"]
except requests.exceptions.RequestException as e:
print(f"Error creating payment intent: {e.response.json() if e.response else e}")
raise
// Ejemplo de uso:
// try:
// payment_data = create_payment_intent(50000, "ORDER_789", {"product_name": "Libro Digital"})
// print(f"Payment URL: {payment_data['payment_url']}")
// except Exception as e:
// print(f"Failed to create payment: {e}")
PHP
<?php
function createPaymentIntent(int $amount, string $orderId, array $metadata = []): array {
$apiBaseUrl = getenv('API_BASE_URL_CRYPTO');
$apiKey = getenv('CRIPTOFACIL_API_KEY');
$merchantId = getenv('MERCHANT_ID');
$appUrl = getenv('APP_URL');
if (!$apiBaseUrl || !$apiKey || !$merchantId || !$appUrl) {
throw new InvalidArgumentException("Missing required environment variables.");
}
$url = "{$apiBaseUrl}/api/v1/payments/intent";
$headers = [
'Authorization: Bearer ' . $apiKey,
'Content-Type: application/json'
];
$data = [
'merchant_id' => $merchantId,
'amount' => $amount,
'currency' => 'CLP',
'order_id' => $orderId,
'external_order_reference' => "SHOP_{$orderId}",
'redirect_urls' => [
'success' => "{$appUrl}/checkout/success?orderId={$orderId}",
'cancel' => "{$appUrl}/checkout/cancel?orderId={$orderId}",
'webhook' => "{$appUrl}/api/webhooks/cripto"
],
'metadata' => array_merge([
'product_name' => 'Producto Ejemplo',
'product_id' => 'SKU_EXAMPLE',
], $metadata)
];
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if (curl_errno($ch)) {
$error_msg = curl_error($ch);
curl_close($ch);
throw new RuntimeException("cURL Error: {$error_msg}");
}
curl_close($ch);
$result = json_decode($response, true);
if ($httpCode >= 400 || !$result || !$result['success']) {
$error_details = $result['message'] ?? json_encode($result);
throw new RuntimeException("Error: HTTP {$httpCode} - {$error_details}");
}
return $result['data'];
}
?>Comisiones y Liquidación
Detalles sobre las comisiones aplicadas y el proceso de liquidación de pagos.
Comisión
0.9%del monto USDT como comisión de plataforma.19%de IVA sobre la comisión de plataforma.- Sin costos ocultos ni cargos adicionales.
- Los gas fees de la red Polygon son pagados por el cliente.
Ejemplo de Cálculo
- Monto que paga el cliente: $50.000 CLP
- Tasa de cambio (ejemplo): 1 USDT = $990 CLP
- Monto en USDT: 50.000 CLP / 990 CLP/USDT = 50.50 USDT
- Comisión plataforma (0.9% de 50.50 USDT): - 0.45 USDT
- IVA sobre comisión (19% de 0.45 USDT): - 0.09 USDT
- **Monto neto recibido (aprox.): 49.96 USDT**
Proceso de Liquidación
- 1.Pago Confirmado: El cliente completa el pago en USDT y la transacción se confirma en la red Polygon (12 bloques).
- 2.Conversión Automática: El monto de USDT recibido se convierte a CLP al tipo de cambio promedio del día.
- 3.Transferencia Bancaria: Los fondos líquidos en CLP se transfieren a tu cuenta bancaria registrada en un plazo de 24 horas hábiles.
Seguridad
Recomendaciones clave para asegurar la integración y proteger tus credenciales.
Protección de API Keys
- Nunca expongas tus API keys (sk_test_ o sk_live_) en el frontend (código JavaScript visible en el navegador) o en repositorios públicos.
- Utiliza variables de entorno en tu servidor backend para almacenar y acceder a las API keys.
- Implementa rotación periódica de tus API keys, especialmente las de producción.
- Considera permisos de acceso granular si tu proveedor de API lo permite.
Verificación de Webhooks
- Valida siempre la firma HMAC (X-Signature) de las peticiones entrantes para asegurar su autenticidad.
- Implementa lógica de idempotencia para evitar procesar el mismo webhook múltiples veces (ej. basado en payment_id o order_id).
- Asegúrate de que tu endpoint de webhook utilice HTTPS.
- Configura limites de tasa (rate limiting) en tu endpoint para prevenir ataques de denegación de servicio (DoS).
Validación de Pagos
- No confíes únicamente en la notificación del webhook. Consulta el estado del pago directamente a través de la API antes de confirmar la orden en tu sistema.
- Verifica que el monto (amount_clp) y la moneda (currency) recibidos coincidan con los esperados para tu orden.
- Maneja adecuadamente todos los estados posibles del pago (pending, processing, confirmed, failed, expired) en tu lógica de negocio.
- Implementa timeouts para pagos pendientes y notifica al usuario si expiran.
Migración de Sandbox a Producción
Pasos para migrar tu integración de pruebas a un entorno de producción real.
Pasos Clave
Validación en Sandbox
Asegúrate de que todas las funcionalidades y flujos de pago funcionen correctamente en el ambiente Sandbox.
Solicitud de Credenciales Live
Contacta a martin@criptofacil.cl para solicitar tus credenciales de producción. Esto puede requerir verificación de tu empresa.
Actualización de Configuración
Reemplaza las URLs base de la API, las API Keys y los Merchant IDs de Sandbox por los de Producción en tu backend.
Configuración de Webhook Producción
Actualiza la URL de tu webhook en el request de creación de pago para que apunte a tu endpoint de producción.
Pruebas Controladas (Go-Live)
Realiza transacciones iniciales con montos bajos y reales para verificar la conexión end-to-end, la recepción de webhooks y la liquidación bancaria.
Monitoreo Continuo
Establece alertas y monitorea tus transacciones y webhooks en producción para detectar cualquier anomalía.