Cancelar Link de Pago
Cancela un link de pago existente. Solo se pueden cancelar links con estado pending o expired.
Endpoint
http
PATCH /v1/payment-links/{hashUrl}/cancelParámetros de ruta
| Parámetro | Tipo | Descripción |
|---|---|---|
hashUrl | string | Hash único del link de pago |
Autenticación
Requiere el header X-API-Key. Consulta la .
Ejemplos de solicitud
:: tab cURL
bash
curl -X PATCH "https://api-pay.zelta.dev/v1/payment-links/abc123def456/cancel" \
-H "X-API-Key: tu-api-key-aqui" \
-H "Content-Type: application/json"::
:: tab Node.js
javascript
const hashUrl = 'abc123def456';
const response = await fetch(
`https://api-pay.zelta.dev/v1/payment-links/${hashUrl}/cancel`,
{
method: 'PATCH',
headers: {
'X-API-Key': process.env.ZELTA_API_KEY,
'Content-Type': 'application/json'
}
}
);
const result = await response.json();
console.log(result);::
:: tab Python
python
import requests
hash_url = 'abc123def456'
response = requests.patch(
f'https://api-pay.zelta.dev/v1/payment-links/{hash_url}/cancel',
headers={
'X-API-Key': 'tu-api-key-aqui',
'Content-Type': 'application/json'
}
)
result = response.json()
print(result)::
:: tab PHP
php
<?php
$hashUrl = 'abc123def456';
$apiKey = getenv('ZELTA_API_KEY');
$ch = curl_init("https://api-pay.zelta.dev/v1/payment-links/{$hashUrl}/cancel");
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'PATCH',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'X-API-Key: ' . $apiKey,
'Content-Type: application/json'
]
]);
$response = curl_exec($ch);
curl_close($ch);
$result = json_decode($response, true);
print_r($result);::
Formato de respuesta
La cancelación devuelve una respuesta compacta con los campos esenciales del link:
json
{
"success": true,
"data": {
"paymentLink": {
"hashUrl": "abc123def456",
"customerName": "Maria Garcia",
"concept": "Pago de servicio mensual",
"amount": 5000,
"status": "cancelled",
"createdAt": "2026-03-13T10:30:00.000Z",
"cancelledAt": "2026-03-13T14:00:00.000Z"
}
},
"message": "Payment link cancelled successfully",
"timestamp": "2026-03-13T14:00:00.000Z"
}Campos de la respuesta
| Campo | Tipo | Descripción |
|---|---|---|
hashUrl | string | Hash único del link de pago |
customerName | string | Nombre del cliente |
concept | string | Concepto o descripción del cobro |
amount | integer | Monto en centavos |
status | string | Estado del link. Siempre "cancelled" después de cancelar |
createdAt | string | Fecha de creación original (ISO 8601) |
cancelledAt | string | Fecha y hora de la cancelación (ISO 8601) |
Códigos de estado
| Código | Descripción |
|---|---|
200 | Link cancelado exitosamente |
401 | API key faltante |
404 | Link de pago no encontrado o API key inválida |
409 | El link no puede ser cancelado (estado inválido) |
429 | Rate limit excedido |
Respuestas de error
Link no encontrado
json
{
"success": false,
"error": {
"code": "ERR_PAYMENT_LINK_NOT_FOUND",
"message": "Payment link not found"
},
"timestamp": "2026-03-13T10:30:00.000Z"
}Estado inválido para cancelación
json
{
"success": false,
"error": {
"code": "ERR_INVALID_STATE_TRANSITION",
"message": "Payment link cannot be cancelled in its current state"
},
"timestamp": "2026-03-13T10:30:00.000Z"
}API key faltante
json
{
"success": false,
"error": {
"code": "ERR_MISSING_API_KEY",
"message": "API key is required"
},
"timestamp": "2026-03-13T10:30:00.000Z"
}Reglas de cancelación
Estados que permiten cancelación
| Estado actual | Se puede cancelar |
|---|---|
pending | Sí |
expired | Sí |
completed | No — el pago ya fue procesado |
cancelled | No — ya está cancelado |
Los links completados no se pueden cancelar
Los links con estado completed no pueden cancelarse porque el pago ya fue procesado. Si necesitas gestionar un pago completado, contacta a soporte.
Ejemplos de implementación
Cancelación básica con manejo de errores
:: tab Node.js
javascript
async function cancelPaymentLink(hashUrl) {
try {
const response = await fetch(
`https://api-pay.zelta.dev/v1/payment-links/${hashUrl}/cancel`,
{
method: 'PATCH',
headers: {
'X-API-Key': process.env.ZELTA_API_KEY,
'Content-Type': 'application/json'
}
}
);
const result = await response.json();
if (!result.success) {
console.error('Error:', result.error.code, result.error.message);
return { success: false, error: result.error };
}
return { success: true, paymentLink: result.data.paymentLink };
} catch (error) {
console.error('Error de red:', error.message);
return { success: false, error: { code: 'NETWORK_ERROR', message: error.message } };
}
}::
:: tab Python
python
import requests
def cancel_payment_link(hash_url):
try:
response = requests.patch(
f'https://api-pay.zelta.dev/v1/payment-links/{hash_url}/cancel',
headers={
'X-API-Key': 'tu-api-key-aqui',
'Content-Type': 'application/json'
}
)
result = response.json()
if not result.get('success'):
print(f"Error: {result['error']['code']} - {result['error']['message']}")
return None
return result['data']['paymentLink']
except requests.exceptions.RequestException as e:
print(f"Error de red: {e}")
return None::
Cancelación segura con verificación de estado
Antes de cancelar, verifica el estado actual del link para manejar cada caso:
javascript
async function safeCancelPaymentLink(hashUrl) {
// Primero, obtener el estado actual
const getResponse = await fetch(
`https://api-pay.zelta.dev/v1/payment-links/${hashUrl}`,
{
headers: {
'X-API-Key': process.env.ZELTA_API_KEY,
'Content-Type': 'application/json'
}
}
);
const getResult = await getResponse.json();
if (!getResult.success) {
return { success: false, error: 'Link de pago no encontrado' };
}
const link = getResult.data.paymentLink;
// Verificar si se puede cancelar
if (link.status === 'completed') {
return {
success: false,
error: 'No se puede cancelar un link con pago completado'
};
}
if (link.status === 'cancelled') {
return {
success: false,
error: 'El link ya está cancelado'
};
}
// Proceder con la cancelación
const cancelResponse = await fetch(
`https://api-pay.zelta.dev/v1/payment-links/${hashUrl}/cancel`,
{
method: 'PATCH',
headers: {
'X-API-Key': process.env.ZELTA_API_KEY,
'Content-Type': 'application/json'
}
}
);
const cancelResult = await cancelResponse.json();
if (!cancelResult.success) {
return { success: false, error: cancelResult.error.message };
}
return {
success: true,
paymentLink: cancelResult.data.paymentLink,
previousStatus: link.status
};
}Casos de uso
Cancelación de orden
Cuando un cliente cancela una orden, cancela también el link de pago asociado:
javascript
async function cancelOrder(orderId, paymentLinkHashUrl) {
// Cancelar el link de pago
const result = await cancelPaymentLink(paymentLinkHashUrl);
if (result.success) {
console.log(`Link de pago cancelado para la orden ${orderId}`);
// Actualizar el estado de la orden en tu sistema
} else {
console.error(`No se pudo cancelar el link: ${result.error.code}`);
// El link puede ya estar completado o cancelado
}
}Limpieza de links expirados
Cancela links expirados para mantener el orden en tu dashboard:
javascript
async function cleanupExpiredLinks() {
// Obtener links expirados
const response = await fetch(
'https://api-pay.zelta.dev/v1/payment-links?status=expired&lim=50',
{
headers: {
'X-API-Key': process.env.ZELTA_API_KEY,
'Content-Type': 'application/json'
}
}
);
const result = await response.json();
if (!result.success) {
console.error('Error al obtener links expirados');
return;
}
let cancelled = 0;
for (const link of result.data.paymentLinks) {
const cancelResult = await cancelPaymentLink(link.hashUrl);
if (cancelResult.success) {
cancelled++;
}
// Respetar el rate limit
await new Promise(resolve => setTimeout(resolve, 1100));
}
console.log(`${cancelled} links expirados cancelados`);
}Cancelación por solicitud del cliente
javascript
app.post('/ordenes/:orderId/cancelar', async (req, res) => {
const order = await getOrder(req.params.orderId);
if (!order || !order.paymentLinkHashUrl) {
return res.status(404).json({ error: 'Orden no encontrada' });
}
const result = await safeCancelPaymentLink(order.paymentLinkHashUrl);
if (result.success) {
// Actualizar la orden en tu sistema
await updateOrderStatus(order.id, 'cancelled');
res.json({
message: 'Orden y link de pago cancelados exitosamente',
cancelledAt: result.paymentLink.cancelledAt
});
} else {
res.status(400).json({ error: result.error });
}
});Buenas prácticas
- Verifica el estado antes de cancelar: consulta el link con antes de intentar cancelar para manejar cada estado apropiadamente.
- Maneja todos los errores: el endpoint puede devolver
404(no encontrado) o409(estado inválido). Prepárate para ambos casos. - Registra las cancelaciones: guarda un log de las cancelaciones con el
hashUrl, la fecha y el motivo para tener trazabilidad. - Rate limiting en lote: si necesitas cancelar múltiples links, espacia las solicitudes para no exceder el límite de 60 por minuto. Agrega un retraso de al menos 1 segundo entre solicitudes.
Siguientes pasos
- — Crea un nuevo link de pago
- — Consulta el estado de un link
- — Obtén todos tus links
- — Recibe notificaciones de cancelación