Primeros pasos
Del alta en el portal al primer evento en tu backend, todo en Sandbox: credenciales, un comercio conectado, un cobro, el pago simulado y el webhook.
Al terminar vas a tener un cobro de Sandbox pagado con un pago simulado y el evento payment_request.payment_received en tu backend. No se mueve plata real.
Antes de empezar
- Una URL HTTPS pública para webhooks. En desarrollo sirve un túnel.
curl, Node 18 o posterior, o Python 3 conrequests.
Definí la URL de la API de Sandbox en tu terminal. La de Producción está en Operación y errores.
export API=https://integration-api.test.chytapay.com.ar1Registrate y configurá
Te registrás vos en el portal, sin esperar a nadie. Arrancás en Sandbox, el ambiente de pruebas.
- Entrá a chytapay.com.ar/portal/login, elegí Crear cuenta, confirmá tu mail y completá los datos de tu empresa. Al terminar, el portal te muestra el
clientIdy elclientSecretde Sandbox. - Guardalos en tu gestor de secretos. El
clientSecretse muestra una sola vez: si lo perdés, rotalo en Credenciales. En este recorrido no los usás: sirven para el OAuth con comercios reales. - Cargá tu URL de webhook HTTPS en Webhooks, pestaña Destino. El token de validación es opcional, de 16 caracteres o más, y llega en el header
validation-token.
2Conseguí un comercio de prueba
La Integration API recibe como Bearer el idToken de una cuenta de comercio vinculada a tu integración. Dura 1 hora.
Atajo en Sandbox: un comercio de prueba
En Sandbox no hace falta OAuth: el portal te da el token de un comercio de prueba ya vinculado. Entrá a Comercios, sección Cuentas, tocá Generar tokens de prueba y guardá el idToken como COMMERCE_TOKEN. Dura 1 hora: cuando venza, generá otro. Para comprobar a qué comercio pertenece el token, llamá a GET /me.
El flujo real: OAuth
En Producción, cada cuenta de comercio autoriza a tu integración con OAuth: authorize, vuelta a tu redirect_uri con code y state, y canje por tokens. La redirect_uri no es la URL de webhook. Consultá cómo conectar comercios con OAuth.
3Creá un cobro
En tu backend, creá el cobro con el token del comercio y un vencimiento entre mañana y 35 días. Mandá "conciliationType": "cuil" y el CUIL o DNI del pagador en customer.taxDocument: el pago se imputa por el CUIL de quien transfiere (por qué CUIL).
cURL
DUE_DATE=$(date -d '+7 days' +%F 2>/dev/null || date -v+7d +%F)
curl -X POST "$API/payment-request" \
-H "Authorization: Bearer $COMMERCE_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"referenceId": "prueba-0001",
"amount": 1500,
"description": "Cobro de prueba",
"dueDates": ["'"$DUE_DATE"'"],
"conciliationType": "cuil",
"sendWhatsappNotification": false,
"sendEmailNotification": false,
"customer": { "name": "Pagador de prueba", "taxDocument": "20123456786" }
}'Node
const dueDate = new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString().slice(0, 10);
const res = await fetch(`${process.env.API}/payment-request`, {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.COMMERCE_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
referenceId: 'prueba-0001',
amount: 1500,
description: 'Cobro de prueba',
dueDates: [dueDate],
conciliationType: 'cuil',
sendWhatsappNotification: false,
sendEmailNotification: false,
customer: { name: 'Pagador de prueba', taxDocument: '20123456786' },
}),
});
const cobro = await res.json();
console.log(res.status, cobro.state, cobro.CVU);Python
import os
import requests
from datetime import date, timedelta
due_date = (date.today() + timedelta(days=7)).isoformat()
res = requests.post(
f"{os.environ['API']}/payment-request",
headers={"Authorization": f"Bearer {os.environ['COMMERCE_TOKEN']}"},
json={
"referenceId": "prueba-0001",
"amount": 1500,
"description": "Cobro de prueba",
"dueDates": [due_date],
"conciliationType": "cuil",
"sendWhatsappNotification": False,
"sendEmailNotification": False,
"customer": {"name": "Pagador de prueba", "taxDocument": "20123456786"},
},
)
cobro = res.json()
print(res.status_code, cobro["state"], cobro["CVU"])Respuesta
{
"type": "standard",
"paymentRequestId": "00000000-0000-0000-0000-000000000000",
"referenceId": "prueba-0001",
"amount": 1500,
"description": "Cobro de prueba",
"dueDates": ["2026-10-07"],
"state": "pending",
"sendWhatsappNotification": false,
"sendEmailNotification": false,
"customer": { "name": "Pagador de prueba", "taxDocument": "20123456786" },
"CVU": "0000000000000000000000",
"bankAccountInfo": { "accountHolderName": "...", "accountHolderTaxId": "...", "bankName": "..." }
}Responde 201 con el cobro en pending. Guardá el CVU en la variable CVU para la etapa 4.
referenceIdlleva de 8 a 100 caracteres (letras, números,-y_) y es único por integración y comercio, cancelados incluidos. Repetido da409ReferenceIdAlreadyExists: para probar de nuevo, cambialo.- Con
amount,sendEmailNotificationes obligatorio.sendWhatsappNotificationes opcional: si lo omitís, rige lo que elegiste en el Portal. En Sandbox,false. - Montos en pesos, con hasta 2 decimales.
Los demás campos, el recargo, el borrador y los lotes están en Crear cobros.
4Simulá el pago
Simulá el pago total en el Portal, en Simulador: poné el CVU del cobro, el monto y los datos de quien paga: CVU origen, nombre origen y, como CUIL origen, el del cobro.
- Con el CUIL del cobro, el pago se imputa y llega
payment_request.payment_received. - Con otro CUIL no concilia y el evento es
payment.unmatched. - Si el evento no te llega, revisá que esté activado en Webhooks y que tengas una URL cargada en Webhooks, pestaña Destino.
Atención: payment.unmatched viene apagado. Activalo en Webhooks, pestaña Eventos: sin él no te enterás de los pagos sin imputar, como el de un tercero con otro CUIL.
5Recibí el evento
Chytapay manda un POST a tu URL de webhook. Respondé 2xx en menos de 5 segundos o reintenta.
| Header | Para qué |
|---|---|
X- |
Firma HMAC-SHA256, t=<unix>,v1=<hex>. Verificala antes de confiar en el evento |
X- |
Igual en todos los reintentos: deduplicá por este id |
validation- |
El token que cargaste con la URL |
El body, recortado:
{
"event": "payment_request.payment_received",
"stateType": "total_payment",
"livemode": false,
"referenceId": "prueba-0001",
"requestedAmount": 1500,
"paidAmount": 1500,
"thisPaymentAmount": 1500,
"remainingAmount": 0,
"reconciledPayerCuil": 20123456786
}Ruteá por event y decidí por stateType: total_payment o partial_payment. livemode es false en Sandbox.
El servidor de ejemplo, la verificación de la firma y los reintentos están en Webhooks. Para probar solo tu endpoint, Webhooks tiene un botón que manda un payment.unmatched de prueba. No existe en producción.
Pasar a producción
Es la misma integración: pedís Producción en Credenciales, y si el chequeo automático la aprueba generás las credenciales de producción con el selector de ambiente en Producción. Si no, el pedido pasa a revisión. Qué revisar antes de cobrar está en Operación y errores.