Buenas prácticas
API v0.1.0En esta página
Checklist para integraciones de producción. Cubre seguridad, robustez, validación y UX.
Seguridad
sk_solo en variables de entorno del servidor. Nunca en repos, bundles JS, o logs.- Verifica firma de webhooks siempre. Sin verificación, cualquiera puede simular eventos.
- TLS obligatorio en URLs de webhook receptoras.
- Rotación de keys periódica. Si expones una key, contacta soporte.
- No loguees
client_secretni OTPs. Sensibles.
Robustez
Idempotency-Keyen cada create, idealmente UUID v4 por intento lógico. Evita cobros dobles.- Reintentos con backoff exponencial ante
5xx. Nunca ante4xx. - Manejo de expiración: si tu UI demora más de 15 min, crea un intent nuevo.
- Procesamiento idempotente de webhooks: el mismo evento puede llegar más de una vez (en futuras versiones).
- Loguea
external_id(pi_xxx) de cada intent. Sirve para soporte y reconciliación.
Validación
- Valida datos venezolanos en tu UI antes de mandar: teléfono
^04\d{9}$, cédula^[VEJGP]\d{6,9}$, RIF^[VEJGP]-\d{8}-\d$. Rutiva re-valida en el borde, pero te ahorra round-trips. amounten céntimos, no decimales. Bs. 500,00 =50000.- Currency case-sensitive:
"VES"o"USD"en mayúsculas.
UX
- Pobla el dropdown de bancos dinámicamente desde
/v1/banks. No hardcodees. - Muestra
bank_referenceal cliente tras succeeded. Es la referencia bancaria, útil para soporte. - Muestra
failure_messagelegible tras failed. Mensajes vienen del banco. - Loading state durante el confirm — el banco demora 1-3s en responder.
Variables de entorno típicas
bash
# Backend del comerciante
RUTIVA_SECRET_KEY=sk_live_xxxxxxxxxxxxxxxx
RUTIVA_BASE_URL=https://rutiva-api.onrender.com
RUTIVA_WEBHOOK_SECRET=whsec_xxxxxxxxxxxxxxxx
# Frontend
VITE_RUTIVA_PUBLISHABLE_KEY=pk_xxx # widget usa como identificador
VITE_RUTIVA_BASE_URL=https://rutiva-api.onrender.comTipos de objeto (TypeScript)
PaymentIntent:
typescript
type PaymentIntent = {
id: string; // UUID interno
external_id: string; // pi_xxx
status: "created" | "succeeded" | "failed" | "canceled";
amount_cents: number;
currency: "VES" | "USD";
customer_phone: string;
customer_id_document: string;
customer_bank_code: string;
bank_reference: string | null; // solo en succeeded
failure_code: string | null; // solo en failed
failure_message: string | null; // solo en failed
expires_at: string; // ISO datetime, 15 min post-create
created_at: string;
updated_at: string;
confirmed_at: string | null;
succeeded_at: string | null;
failed_at: string | null;
canceled_at: string | null;
// client_secret aparece SOLO en la response del create.
};Bank:
typescript
type Bank = {
code: string; // "0114"
name: string; // "Banco habilitado"
};WebhookEvent:
typescript
type WebhookEvent = {
type: "payment_intent.created"
| "payment_intent.succeeded"
| "payment_intent.failed"
| "payment_intent.canceled";
data: PaymentIntent;
};Recursos
- Swagger interactivo: rutiva-api.onrender.com/docs
- Estado del servicio: rutiva-api.onrender.com/health
- Soporte:
dev@rutiva.dev