Saltearse al contenido

Pago con tarjeta tokenizada

Útil cuando tu cliente compra varias veces y no querés que retipee los datos de la tarjeta en cada compra. Después del catastro inicial, cada compra es un click: el cliente elige su tarjeta guardada y autoriza el cobro.

El flow tiene dos etapas: catastro (una vez por cliente, abre un iframe) y charge (cada cobro, server-to-server con el token guardado).

Diagrama del catastro

sequenceDiagram
    autonumber
    participant Cliente
    participant TuApp as Tu app
    participant Ingalca as INGALCA Pay
    participant Dinelco

    TuApp->>Ingalca: POST /v1/cards
{customer.customerId} Ingalca->>Dinelco: Crear sesión registry Dinelco-->>Ingalca: integrity_token + session_id Ingalca-->>TuApp: card_xxx + integrity_token + validate_url TuApp-->>Cliente: Embed iframe (validate_url) Cliente->>Dinelco: Tipear tarjeta + 3DS OTP Dinelco-->>Ingalca: Callback con paymentToken Ingalca->>Ingalca: Marcar card registered Ingalca->>TuApp: webhook card.registered (con token_id) TuApp-->>Cliente: "Tarjeta guardada"

Paso 1 — iniciar catastro

Ventana de terminal
curl -X POST https://api.pay.ingalca.com/v1/cards \
-H "Authorization: Bearer sk_test_..." \
-H "Content-Type: application/json" \
-d '{
"provider": "dinelco",
"target_origin": [
"https://tu-checkout.com",
"https://app.tu-checkout.com"
],
"customer": {
"customerId": "user_42",
"name": "Juan",
"lastname": "Pérez",
"email": "juan@example.com",
"phone": "+595981234567"
}
}'

Respuesta:

{
"data": {
"card_id": "card_xyz789",
"status": "pending",
"registration": {
"integrity_token": "eyJhbGc...",
"session_id": 123456789,
"validate_url": "https://test-checkout.dinelco.com.py:50106/registry?token=eyJhbGc..."
}
}
}

Paso 2 — embeber el iframe

En tu frontend:

<iframe
src="<validate_url>"
width="100%"
height="600"
style="border: 0"
allow="payment"
></iframe>

El cliente tipea la tarjeta dentro del iframe (que sirve directamente desde Dinelco — vos nunca ves los datos sensibles). Al pasar 3DS, Dinelco le pega un callback a INGALCA Pay con el paymentToken.

Paso 3 — recibir webhook de catastro

{
"event_type": "card.registered",
"data": {
"card_id": "card_xyz789",
"customer_id": "user_42",
"status": "registered",
"provider": "dinelco",
"brand": "Visa",
"last_four": "1096",
"expires": "12/30"
}
}

Ya podés cobrar con esta card.

Diagrama del charge

sequenceDiagram
    autonumber
    participant TuApp as Tu app
    participant Ingalca as INGALCA Pay
    participant Dinelco

    TuApp->>Ingalca: POST /v1/cards/{card_id}/charge
{amount, reference} Ingalca->>Dinelco: POST api/v3/payment
(con tokenId) Dinelco-->>Ingalca: status + responseCode Ingalca-->>TuApp: payment confirmed o failed Ingalca->>TuApp: webhook payment.confirmed o payment.failed

Paso 4 — cobrar

Ventana de terminal
curl -X POST https://api.pay.ingalca.com/v1/cards/card_xyz789/charge \
-H "Authorization: Bearer sk_test_..." \
-H "Content-Type: application/json" \
-d '{
"amount": 50000,
"reference": "ORDEN-12345"
}'

A diferencia del checkout, el cobro es sincrónico — la respuesta ya tiene el resultado:

{
"data": {
"id": "pay_def456",
"status": "confirmed",
"amount": 50000,
"provider_data": {
"operation_number": "0000123456",
"authorization_number": "ABC123"
}
}
}

Estados de la tarjeta

stateDiagram-v2
    [*] --> pending: POST /v1/cards
    pending --> registered: callback OK + 3DS pasado
    pending --> invalid: callback rechazado
    registered --> deleted: DELETE /v1/cards/{id}*
    invalid --> [*]
    deleted --> [*]

* Hoy DELETE devuelve 501 — Dinelco no expone endpoint de unregister. Si querés “borrar” una tarjeta, marcala como inactiva en tu app y dejá de usarla; INGALCA Pay no la va a cobrar si no se la pedís.

Notas

  • El paymentToken se guarda encriptado del lado nuestro y nunca se devuelve en respuestas. Vos solo manejás el card_id (card_xxx).
  • 3DS es obligatorio en el catastro de Dinelco — el cliente siempre pasa por el OTP.
  • El customerId que mandamos a Dinelco es nuestro public_id interno (cust_xxx), no el external_id que vos enviás. Esto evita colisiones cross-tenant en sandboxes compartidos.