Este servicio es el único punto de la iglesia autorizado a procesar cobros con tarjeta. Las aplicaciones (Instituto, ofrendas, eventos) no manejan datos de tarjeta: le piden un cobro a este gateway y redirigen al usuario a CardNet.
Regla inviolable: nunca envíes número de tarjeta, CVV ni fecha de
expiración a este gateway. Las peticiones que incluyan esos campos son rechazadas
con 422. La tarjeta se digita únicamente en las pantallas de CardNet.
POST /api/v1/checkout con el monto y su referencia interna.return_url.
Los parámetros que llegan a tu return_url son solo informativos, para
pintar una pantalla. El estado real se confirma por webhook o
consultando GET /api/v1/checkout/{session_id}.
Toda petición autenticada lleva cuatro encabezados. La firma se calcula sobre:
MÉTODO\nRUTA\nTIMESTAMP\nNONCE\nSHA256(cuerpo)
X-API-Key — la llave de tu aplicación.X-Timestamp — hora Unix; se acepta un desfase de 5 minutos.X-Nonce — UUID único por petición (evita reenvíos).X-Signature — base64 del HMAC-SHA256 firmado con tu secreto.Idempotency-Key — obligatorio al crear cobros y devoluciones.$body = json_encode($payload, JSON_UNESCAPED_SLASHES);
$timestamp = (string) time();
$nonce = (string) Str::uuid();
$path = '/api/v1/checkout';
$stringToSign = "POST\n{$path}\n{$timestamp}\n{$nonce}\n" . hash('sha256', $body);
$signature = base64_encode(hash_hmac('sha256', $stringToSign, $apiSecret, true));
$response = Http::withHeaders([
'X-API-Key' => $apiKey,
'X-Timestamp' => $timestamp,
'X-Nonce' => $nonce,
'X-Signature' => $signature,
'Idempotency-Key' => $idempotencyKey, // el mismo si reintentas
'Content-Type' => 'application/json',
])->withBody($body, 'application/json')->post('https://pagos.iglesiamontededios.org.do' . $path);
La Idempotency-Key debe ser la misma en un reintento del mismo cobro:
así un doble clic del usuario no genera dos cargos.
POST /api/v1/checkout
{
"amount": 800.00,
"description": "Inscripción ciclo 2026-2",
"external_ref": "INS-21620",
"return_url": "https://instituto.iglesiamontededios.org.do/pago/retorno",
"cancel_url": "https://instituto.iglesiamontededios.org.do/pago/cancelado",
"customer_name": "Juan Pérez",
"customer_email": "juan@example.com"
}
Respuesta 201:
{
"session_id": "01HX5K2VJT9N3Q7ZMFJCPB8YGE",
"transaction_id": "01HX5K2VJT9N3Q7ZMFJCPB8YGF",
"order_number": "ORD20260827164959AB12CD",
"status": "pending",
"expires_at": "2026-08-27T21:19:59+00:00",
"redirect": {
"url": "https://ecommerce.cardnet.com.do/authorize",
"method": "POST",
"fields": { "SESSION": "UI_ABC123" }
}
}
external_ref es tu identificador interno. Es la pieza que te permite
conectar el pago con tu propio registro cuando llegue el webhook.
<form id="cardnet" method="POST" action="{{ $redirect['url'] }}">
<input type="hidden" name="SESSION" value="{{ $redirect['fields']['SESSION'] }}">
</form>
<script>document.getElementById('cardnet').submit();</script>
GET /api/v1/checkout/{session_id}
GET /api/v1/transactions/{transaction_id}
POST /api/v1/transactions/{transaction_id}/refund
{ "amount": 800.00, "reason": "El estudiante canceló su inscripción" }
La devolución queda pending: CardNet no permite devolver por API en este
flujo, así que el personal la tramita ante el banco y la marca como completada desde
el panel.
El gateway notifica a la webhook_url registrada para tu aplicación.
Verifica siempre la firma antes de procesar.
payment.captured — el cobro fue aprobado.payment.failed — el banco lo rechazó.payment.cancelled — el usuario canceló.payment.expired — la sesión venció sin completarse.refund.completed — una devolución fue confirmada.{
"id": "01HX5K...",
"event": "payment.captured",
"created_at": "2026-08-27T21:05:12+00:00",
"data": {
"transaction_id": "01HX5K2VJT9N3Q7ZMFJCPB8YGF",
"external_ref": "INS-21620",
"status": "captured",
"amount": 800.00,
"currency": "DOP",
"auth_code": "A1B2C3"
}
}
Encabezados: X-Gateway-Event, X-Gateway-Delivery y
X-Gateway-Signature = base64 del HMAC-SHA256 del cuerpo crudo,
firmado con tu secreto. Responde 2xx o el gateway reintentará.
201 — sesión de pago creada.401 / 403 — firma inválida, vencida o aplicación inactiva.422 — datos inválidos, o se enviaron datos de tarjeta.429 — se excedió el límite de peticiones.502 — CardNet no respondió o rechazó la creación de la sesión.