Inicio Rápido
Bienvenido a la API de Zelta Pay. Esta guía te ayudará a crear tu primer link de pago y entender los fundamentos de nuestra API.
¿Prefieres usar el dashboard?
Si prefieres crear links de pago sin código, consulta la guía del y .
Requisitos previos
Antes de comenzar, asegúrate de tener:
- Una cuenta de Zelta Pay
- Una API key (obtenida desde tu dashboard)
- Conocimiento básico de solicitudes HTTP
- Un entorno de desarrollo listo
Paso 1: Obtén tu API Key
- Inicia sesión en tu
- Navega a API Keys
- Ingresa un alias descriptivo y haz clic en + Crear
- Dale un alias descriptivo (ej.
mi-app-produccion) - Copia la API key generada y guárdala de forma segura
Buena práctica de seguridad
Nunca guardes API keys en el control de versiones. Usa variables de entorno o gestión segura de secretos.
Paso 2: Haz tu primera llamada a la API
Probemos tu API key listando tus links de pago existentes:
:: tab cURL
curl -X GET "https://api-pay.zelta.dev/v1/payment-links" \
-H "X-API-Key: tu-api-key-aqui" \
-H "Content-Type: application/json"::
:: tab Node.js
const response = await fetch('https://api-pay.zelta.dev/v1/payment-links', {
method: 'GET',
headers: {
'X-API-Key': 'tu-api-key-aqui',
'Content-Type': 'application/json'
}
});
const result = await response.json();
console.log(result);::
:: tab Cloudflare Workers
export default {
async fetch(request, env, ctx) {
const response = await fetch('https://api-pay.zelta.dev/v1/payment-links', {
method: 'GET',
headers: {
'X-API-Key': env.ZELTA_API_KEY,
'Content-Type': 'application/json'
}
});
const result = await response.json();
return new Response(JSON.stringify(result), {
headers: { 'Content-Type': 'application/json' }
});
}
};::
:: tab Hono
import { Hono } from 'hono';
import { cors } from 'hono/cors';
type Bindings = {
ZELTA_API_KEY: string;
};
const app = new Hono<{ Bindings: Bindings }>();
app.use('*', cors());
app.get('/payment-links', async (c) => {
const response = await fetch('https://api-pay.zelta.dev/v1/payment-links', {
method: 'GET',
headers: {
'X-API-Key': c.env.ZELTA_API_KEY,
'Content-Type': 'application/json'
}
});
const result = await response.json();
return c.json(result);
});
export default app;::
:: tab Python
import requests
response = requests.get(
'https://api-pay.zelta.dev/v1/payment-links',
headers={
'X-API-Key': 'tu-api-key-aqui',
'Content-Type': 'application/json'
}
)
result = response.json()
print(result)::
Paso 3: Crea tu primer link de pago
Ahora creemos un link de pago:
:: tab cURL
curl -X POST "https://api-pay.zelta.dev/v1/payment-links" \
-H "X-API-Key: tu-api-key-aqui" \
-H "Content-Type: application/json" \
-d '{
"concept": "Pago de prueba",
"amount": 100,
"customerName": "Juan Pérez",
"isTest": true
}'::
:: tab Node.js
const response = await fetch('https://api-pay.zelta.dev/v1/payment-links', {
method: 'POST',
headers: {
'X-API-Key': 'tu-api-key-aqui',
'Content-Type': 'application/json'
},
body: JSON.stringify({
concept: 'Pago de prueba',
amount: 100,
customerName: 'Juan Pérez',
isTest: true
})
});
const result = await response.json();
console.log(result);::
:: tab Cloudflare Workers
export default {
async fetch(request, env, ctx) {
const response = await fetch('https://api-pay.zelta.dev/v1/payment-links', {
method: 'POST',
headers: {
'X-API-Key': env.ZELTA_API_KEY,
'Content-Type': 'application/json'
},
body: JSON.stringify({
concept: 'Pago de prueba',
amount: 100,
customerName: 'Juan Pérez',
isTest: true
})
});
const result = await response.json();
return new Response(JSON.stringify(result), {
headers: { 'Content-Type': 'application/json' }
});
}
};::
:: tab Hono
import { Hono } from 'hono';
import { cors } from 'hono/cors';
type Bindings = {
ZELTA_API_KEY: string;
};
const app = new Hono<{ Bindings: Bindings }>();
app.use('*', cors());
app.post('/payment-links', async (c) => {
const response = await fetch('https://api-pay.zelta.dev/v1/payment-links', {
method: 'POST',
headers: {
'X-API-Key': c.env.ZELTA_API_KEY,
'Content-Type': 'application/json'
},
body: JSON.stringify({
concept: 'Pago de prueba',
amount: 100,
customerName: 'Juan Pérez',
isTest: true
})
});
const result = await response.json();
return c.json(result);
});
export default app;::
:: tab Python
import requests
response = requests.post(
'https://api-pay.zelta.dev/v1/payment-links',
headers={
'X-API-Key': 'tu-api-key-aqui',
'Content-Type': 'application/json'
},
json={
'concept': 'Pago de prueba',
'amount': 100,
'customerName': 'Juan Pérez',
'isTest': True
}
)
result = response.json()
print(result)::
Paso 4: Entiende la respuesta
Una respuesta exitosa se verá así:
{
"success": true,
"data": {
"paymentLink": {
"id": "pl_1234567890abcdef",
"paymentLinkUrl": "https://pay.zelta.dev/abc123",
"customerName": "Juan Pérez",
"concept": "Pago de prueba",
"amount": 100,
"status": "pending",
"createdAt": "2024-01-15T10:30:00.000Z",
"expiresAt": "2024-01-18T10:30:00.000Z",
"isTest": true
}
},
"message": "Payment link created successfully",
"timestamp": "2024-01-15T10:30:00.000Z"
}Campos clave de la respuesta
paymentLinkUrl: La URL que tu cliente usará para pagarid: Identificador único del link de pagostatus: Estado actual (siempre "pending" para links nuevos)expiresAt: Cuándo expira el link (3 días desde la creación vía API)
Paso 5: Gestiona el pago
Una vez que tengas la URL del link de pago, puedes:
- Enviarlo a tu cliente por correo, SMS o mostrarlo en tu sitio web
- Redirigirlo al portal de pago
- Monitorear el estado llamando a la API o configurando webhooks
// Redirigir al cliente a la página de pago
window.location.href = result.data.paymentLink.paymentLinkUrl;Paso 6: Configura webhooks (opcional)
Para recibir notificaciones en tiempo real cuando se completen los pagos:
- Ve a Webhooks en tu dashboard
- Agrega la URL de tu webhook (debe ser HTTPS)
- Selecciona los eventos que quieres recibir
- Prueba tu endpoint de webhook
:: tab Node.js (Express)
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
const signature = req.headers['zeltapay-signature'];
const timestamp = req.headers['zeltapay-timestamp'];
// Verificar firma (importante para seguridad)
if (!verifySignature(req.body.toString(), timestamp, signature)) {
return res.status(401).json({ error: 'Invalid signature' });
}
const payload = JSON.parse(req.body);
if (payload.type === 'payment.success') {
console.log('Pago completado:', payload.transaction.amount);
// Actualiza tu base de datos, envía correo de confirmación, etc.
}
res.status(200).json({ received: true });
});::
:: tab Cloudflare Workers
export default {
async fetch(request, env, ctx) {
if (request.method !== 'POST') {
return new Response('Method not allowed', { status: 405 });
}
try {
const signature = request.headers.get('zeltapay-signature');
const timestamp = request.headers.get('zeltapay-timestamp');
const rawBody = await request.text();
if (!await verifySignature(rawBody, timestamp, signature, env.WEBHOOK_SECRET)) {
return new Response(JSON.stringify({ error: 'Invalid signature' }), {
status: 401,
headers: { 'Content-Type': 'application/json' }
});
}
const payload = JSON.parse(rawBody);
if (payload.type === 'payment.success') {
console.log('Pago completado:', payload.transaction.amount);
}
return new Response(JSON.stringify({ received: true }), {
status: 200,
headers: { 'Content-Type': 'application/json' }
});
} catch (error) {
return new Response(JSON.stringify({ error: 'Processing failed' }), {
status: 500,
headers: { 'Content-Type': 'application/json' }
});
}
}
};::
:: tab Hono
import { Hono } from 'hono';
type Bindings = {
WEBHOOK_SECRET: string;
};
const app = new Hono<{ Bindings: Bindings }>();
app.post('/webhook', async (c) => {
try {
const signature = c.req.header('zeltapay-signature');
const timestamp = c.req.header('zeltapay-timestamp');
if (!signature || !timestamp) {
return c.json({ error: 'Missing required headers' }, 400);
}
const rawBody = await c.req.text();
if (!await verifySignature(rawBody, timestamp, signature, c.env.WEBHOOK_SECRET)) {
return c.json({ error: 'Invalid signature' }, 401);
}
const payload = JSON.parse(rawBody);
if (payload.type === 'payment.success') {
console.log('Pago completado:', payload.transaction.amount);
}
return c.json({ received: true });
} catch (error) {
return c.json({ error: 'Processing failed' }, 500);
}
});
export default app;::
Siguientes pasos
- — API keys y rate limiting
- — Opciones avanzadas y validación
- — Notificaciones de pago en tiempo real
- — Documentación completa de endpoints
Problemas comunes
401 Unauthorized
- Verifica que tu API key sea correcta
- Asegúrate de incluir el header
X-API-Key - Confirma que la API key esté activa en tu dashboard
400 Bad Request
- Verifica que todos los campos requeridos estén incluidos
- Asegúrate de que el monto esté en centavos (ej. 100 = $1.00)
- Confirma que el formato JSON sea correcto
429 Too Many Requests
- Has excedido el rate limit (60 solicitudes por minuto)
- Espera antes de hacer más solicitudes
- Considera implementar cola de solicitudes