Crear cobros
Cómo crear cobros uno por uno o en bulk, con vencimientos, recargo, estados, avisos al pagador y reintentos seguros.
En esta página podés consultar cómo crear, seguir y cancelar cobros, uno por uno o hasta 100 por llamada. Necesitás una cuenta de comercio conectada y su id_token en Authorization: Bearer: consultá Conectar comercios.
Cómo pasa un cobro de un estado a otro.
draftpasa apendingcuando le cargás el monto con PATCH.- Si ya entró plata y falta menos de $1, el cobro cuenta como
total_payment; sin pagos sigue abierto. pendingpasa atotal_paymentcon un pago total, apartial_paymentcon un pago parcial y aoverduesi vence sin pagos.partial_paymentpasa atotal_paymentcuando se paga el saldo y apartial_overduesi vence antes.draftypendingpasan acanceledcuando los cancelás, si no recibieron ningún pago.- Un cobro con pagos pasa a
partially_refundedorefundedcuando se lo devuelve, en parte o por completo.
1Creá un cobro
Identificás cada cobro con tu referenceId, que vuelve en cada respuesta y evento.
En tu backend, creá el cobro en Sandbox:
cURL
curl -X POST https://integration-api.test.chytapay.com.ar/payment-request \
-H "Authorization: Bearer $ID_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"referenceId": "factura-1001",
"amount": 25000,
"description": "Cuota de octubre",
"dueDates": ["<FECHA_1>", "<FECHA_2>"],
"surcharge": { "type": "percentage", "value": 10 },
"conciliationType": "cuil",
"sendWhatsappNotification": false,
"sendEmailNotification": true,
"customer": {
"name": "Nombre Apellido",
"email": "[email protected]",
"taxDocument": "20000000001"
},
"metadata": { "orden": "1001" }
}'Node
const BASE = 'https://integration-api.test.chytapay.com.ar';
const res = await fetch(`${BASE}/payment-request`, {
method: 'POST',
headers: {
Authorization: `Bearer ${idToken}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
referenceId: 'factura-1001',
amount: 25000,
description: 'Cuota de octubre',
dueDates: ['<FECHA_1>', '<FECHA_2>'],
surcharge: { type: 'percentage', value: 10 },
conciliationType: 'cuil',
sendWhatsappNotification: false,
sendEmailNotification: true,
customer: {
name: 'Nombre Apellido',
email: '[email protected]',
taxDocument: '20000000001',
},
metadata: { orden: '1001' },
}),
});
const cobro = await res.json(); // 201Python
import requests
BASE = "https://integration-api.test.chytapay.com.ar"
res = requests.post(
f"{BASE}/payment-request",
headers={"Authorization": f"Bearer {id_token}"},
json={
"referenceId": "factura-1001",
"amount": 25000,
"description": "Cuota de octubre",
"dueDates": ["<FECHA_1>", "<FECHA_2>"],
"surcharge": {"type": "percentage", "value": 10},
"conciliationType": "cuil",
"sendWhatsappNotification": False,
"sendEmailNotification": True,
"customer": {
"name": "Nombre Apellido",
"email": "[email protected]",
"taxDocument": "20000000001",
},
"metadata": {"orden": "1001"},
},
)
cobro = res.json() # 201Respuesta
{
"type": "standard",
"paymentRequestId": "<uuid del cobro>",
"referenceId": "factura-1001",
"amount": 25000,
"description": "Cuota de octubre",
"dueDates": ["<FECHA_1>", "<FECHA_2>"],
"state": "pending",
"surcharge": { "type": "percentage", "value": 10 },
"calculatedAmounts": [
{ "dueDate": "<FECHA_1>", "amount": 25000, "isOriginalAmount": true },
{ "dueDate": "<FECHA_2>", "amount": 27500, "surchargeApplied": 2500 }
],
"sendWhatsappNotification": false,
"sendEmailNotification": true,
"metadata": { "orden": "1001" },
"customer": {
"name": "Nombre Apellido",
"email": "[email protected]",
"taxDocument": "20000000001"
},
"CVU": "<CVU de 22 dígitos>",
"bankAccountInfo": {
"accountHolderName": "<titular de la cuenta de comercio>",
"accountHolderTaxId": "<CUIT del titular>",
"bankName": "<banco>"
}
}Reemplazá <FECHA_1> y <FECHA_2> por fechas futuras dentro de 35 días (por ejemplo, hoy +7 y +14 días). El ejemplo concilia por CUIL, el modo recomendado: antes, validá el documento.
Qué devuelve
201 con paymentRequestId, state (pending, o draft sin monto), CVU y bankAccountInfo (adónde transfiere el pagador) y, con monto y 2 fechas, calculatedAmounts (cada vencimiento con recargo). No devuelve conciliationType ni un surcharge de tipo none; en modo CVU omite customer.taxDocument.
2Consultá un cobro
Pedilo con GET /payment-request/{referenceId}:
curl https://integration-api.test.chytapay.com.ar/payment-request/factura-1001 \
-H "Authorization: Bearer $ID_TOKEN"Devuelve el cobro con state actualizado; omite customer.taxDocument, conciliationType y las fechas de aviso. Si no existe para la cuenta de comercio, da 404. GET y PATCH devuelven dueDates y calculatedAmounts[].dueDate como fecha UTC, sin la hora: conservá el vencimiento enviado.
Qué incluye el listado
GET /payment-request?startDate=AAAA-MM-DD&endDate=AAAA-MM-DD lista cobros abiertos, con una excepción: también devuelve los checkouts que vencieron o se cancelaron sin pagador. Ambas fechas son opcionales. Los demás cobros pagados, vencidos o cancelados dejan de aparecer: seguí su estado con el GET por referenceId o los webhooks. Cada ítem trae status, amount (0 en borradores), dueDate (primer vencimiento en UTC), paidAmount, createdAt y customer sin taxDocument, con phoneNumber como string normalizado. status usa los estados públicos en inglés: draft, pending, partial_payment, total_payment, overdue, partial_overdue, canceled, refunded y partially_refunded.
3Duplicados y reintentos
No hay idempotency key: el referenceId es único por integración y cuenta de comercio, incluidos los cancelados. Repetirlo da 409 y no devuelve el cobro existente:
{
"error": "ReferenceIdAlreadyExists",
"message": "The provided reference ID already exists for this client",
"referenceId": "factura-1001"
}Usá el id de tu entidad (factura, pedido, cuota), no uno por intento. Si un create da timeout:
- Hacé
GET /payment-request/{referenceId}. Si da 200, el cobro se creó: usá esa respuesta. - Si da 404, reintentá el
POSTcon el mismo cuerpo yreferenceId. - Si el
POSTda 409, otro intento lo creó: volvé al paso 1.
Si el cobro del GET no coincide con lo que querías crear, reusaste por error un referenceId viejo.
4Cancelá un cobro
Usá POST /payment-request/{referenceId}/cancel, sin cuerpo:
cURL
curl -X POST https://integration-api.test.chytapay.com.ar/payment-request/factura-1001/cancel \
-H "Authorization: Bearer $ID_TOKEN"Respuesta
{ "referenceId": "factura-1001", "state": "canceled" }Solo se cancelan cobros en draft o pending sin pagos: si no, 409 PaymentRequestCannotBeCanceled. No genera evento: la respuesta 200 es la confirmación. Si después entra una transferencia, llega payment.unmatched con reason: "canceled", que es opt-in.
Campos
Los campos de un cobro estándar. Los opcionales que no usás se omiten, no van en null. Los campos desconocidos se ignoran; los prohibidos por nombre dan 400.
| Campo | Obligatorio | Reglas |
|---|---|---|
referenceId |
Sí | 8 a 100 caracteres: letras, números, - y _. Ver duplicados. |
description |
Sí | La ve el pagador. 3 a 500 caracteres. |
due |
Sí | 1 o 2 fechas: ver vencimientos. |
customer |
Sí | El pagador (tabla de abajo). |
amount |
No | Pesos, mayor a 0, mandá hasta 2 decimales, tope 200.000.000. Sin él, nace borrador. |
surcharge |
Con monto y 2 fechas | { "type", "value" } del segundo vencimiento. Prohibido sin amount. |
send |
No | Avisos por WhatsApp. Si lo omitís con monto, rige lo que elegiste en el Portal (WhatsApp). Sin monto, solo false. |
send |
Con monto | Avisos por email. Sin monto, solo false. |
send |
No | Ver confirmación de pago. |
reminder |
No | YYYY-. Reemplaza el recordatorio previo. Solo con monto. |
deferred |
No | YYYY-. Difiere el aviso inicial. Solo con monto. |
conciliation |
No | cvu (default) o cuil, el recomendado. |
webhook |
No | HTTPS, hasta 2048 caracteres. Reemplaza la URL de webhook para este cobro. |
metadata |
No | Strings: hasta 50 claves de 40 caracteres, valores de 500, 8 KB. Vuelve en el GET y los eventos. |
Campo de customer |
Obligatorio | Reglas |
|---|---|---|
name |
Sí | 2 a 150 caracteres. |
tax |
Con conciliation |
CUIL de 11 dígitos o DNI de 7 u 8. En modo CVU se ignora. |
email |
Con send |
Válido, hasta 320 caracteres. |
phone |
Con send |
{ "country, 6 a 20 caracteres: dígitos, espacios y + -. |
Fuera de estas reglas, 400 con el detalle: consultá los errores.
Vencimientos y recargo
dueDates lleva 1 o 2 fechas, posteriores a hoy y a 35 días o menos:
| Formato | Ejemplo | Vence |
|---|---|---|
YYYY- |
"<FECHA_ |
Al terminar ese día, hora Argentina. |
YYYY- |
"<FECHA_ |
En ese minuto. Sin zona es -; acepta Z o un offset. Al menos 3 minutos en el futuro. |
En borradores con hora, mandá siempre el offset explícito (por ejemplo, <FECHA_1>T18:30-03:00). Entre las 21 y las 24 de Argentina, la validación toma el día UTC: usá pasado mañana para una fecha sin hora.
Con hora, el cobro es de corta duración. Con 2 fechas, el segundo elemento de dueDates lleva surcharge, obligatorio con monto (Chytapay no las reordena). Se debe amount hasta el primer vencimiento y amount más el recargo desde el día siguiente.
type es percentage (0 a 100, sobre el monto), fixed (pesos, hasta 200.000.000) o none (value: 0). Con amount: 25000 y { "type": "percentage", "value": 10 }, el segundo vencimiento es de 27.500, en calculatedAmounts.
Cobros de corta duración
Para reservas, entradas o cualquier cobro que tiene que cerrarse en un horario, mandá el vencimiento con hora: "<FECHA_1>T18:30". Cambia varias cosas respecto de una fecha sola:
| Fecha sola | Con hora | |
|---|---|---|
| Vence | Al terminar ese día, hora Argentina | En ese minuto. Sin zona es - |
| Vencimientos | 1 o 2, con recargo en el segundo | Uno solo, sin recargo |
| Evento al vencer | Ninguno | payment_ |
| Avisos al pagador | Recordatorio un día antes | Con menos de 24 horas no hay recordatorio previo: quedan el inicial y el del día |
| En bulk | Sí | No, da 400 |
Si el cobro se paga en el widget, el cobro de checkout vence entre 3 y 60 minutos.
Borrador sin monto
Sin amount, el cobro nace en draft, con un vencimiento, sin recargo ni avisos (flags solo en false, fechas de aviso prohibidas). Su CVU no recibe pagos para ese borrador: una transferencia queda sin imputar (no_pending). Completalo con PATCH /payment-request/{referenceId}:
cURL
curl -X PATCH https://integration-api.test.chytapay.com.ar/payment-request/factura-1002 \
-H "Authorization: Bearer $ID_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "amount": 18000 }'Respuesta
{
"referenceId": "factura-1002",
"previousAmount": null,
"amount": 18000,
"description": "Inscripción",
"state": "pending",
"dueDates": ["<FECHA_1>"]
}- Solo en
draftsin pagos; si no, 409. - Pasa a
pending. Un borrador no envía avisos, ni después del PATCH. - Si no lo completás, Chytapay lo descarta a partir de una hora sin modificaciones.
Estados
Create, GET, cancel, PATCH y bulk devuelven state, y los eventos payment_request.*, stateType. No existe PAID: es total_payment.
| Estado | Significa |
|---|---|
draft |
Borrador sin monto. |
pending |
Esperando el pago. |
partial_ |
Pago parcial, queda saldo. |
total_ |
Pagado. |
overdue |
Venció sin pagos. |
partial_ |
Venció con un pago parcial. |
canceled |
Cancelado. |
refunded |
Devuelto por completo. Ver devoluciones. |
partially_ |
Devuelto en parte. |
Con 2 fechas, el cobro sigue abierto hasta el segundo vencimiento. Una fecha por día vence a las 00:00 hora Argentina, sin evento; una con hora vence en ese minuto con payment_request.expired. Consultá los eventos en Webhooks.
Avisos al pagador
Un aviso es un WhatsApp o email de Chytapay al pagador (no un evento a tu backend). Los canales se eligen en los campos, solo con monto. Con un pago parcial los recordatorios salen con el saldo; pagado, vencido o cancelado, no salen.
Cuándo sale cada aviso
Los recordatorios salen a las 10, hora Argentina.
Ver el calendario de avisos
| Aviso | Cuándo | Monto |
|---|---|---|
| Inicial | Al crear, o el día de deferred |
Primer vencimiento, sin recargo |
| Recordatorio previo | Un día antes del primer vencimiento, o el día de reminder |
Primer vencimiento, sin recargo |
| Día del vencimiento | Ese día | Primer vencimiento, sin recargo |
| Primer vencimiento pasado (2 fechas) | El día siguiente | Segundo vencimiento, con recargo |
| Día del segundo vencimiento (2 fechas) | Ese día | Segundo vencimiento, con recargo |
Las dos fechas son posteriores a hoy y anteriores al primer vencimiento, y reminderNotificationDate además posterior a deferredInitialNotificationDate.
Confirmación de pago
El aviso de pago recibido por WhatsApp lo controla sendWhatsappPaymentConfirmation, no sendWhatsappNotification:
| Valor | Modo CVU | Modo CUIL |
|---|---|---|
| Omitido | Sale, en pagos totales y parciales | No sale |
true |
Sale, en pagos totales y parciales | Solo en el pago total |
false |
No sale | No sale |
En modo CUIL el pagador puede pedirla con "Recibir confirmación de pago", y false no lo apaga.
Creá cobros en bulk
POST /payment-request/bulk crea de 1 a 100 cobros, todos o ninguno. Cada ítem es un cobro individual, salvo que:
- Siempre concilia por CUIL:
customer.taxDocumentes obligatorio. - El mismo documento dos veces en el lote da 422.
- Una fecha con hora da 400.
- No mandes
reminderNotificationDatenideferredInitialNotificationDate: no están soportadas en bulk. conciliationType,type,expiresInMinutesywebhookUrlestán prohibidos: los eventos van a la URL de la integración.
En tu backend, mandá el lote:
cURL
curl -X POST https://integration-api.test.chytapay.com.ar/payment-request/bulk \
-H "Authorization: Bearer $ID_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"paymentRequests": [
{
"referenceId": "cuota-2026-10-001",
"amount": 12000,
"description": "Cuota de octubre",
"dueDates": ["<FECHA_1>"],
"sendWhatsappNotification": false,
"sendEmailNotification": false,
"customer": { "name": "Nombre Apellido", "taxDocument": "20000000001" }
},
{
"referenceId": "cuota-2026-10-002",
"amount": 12000,
"description": "Cuota de octubre",
"dueDates": ["<FECHA_1>"],
"sendWhatsappNotification": false,
"sendEmailNotification": false,
"customer": { "name": "Otro Pagador", "taxDocument": "30405060" }
}
]
}'Respuesta
{
"batchId": "<uuid del lote>",
"total": 2,
"created": 2,
"sharedCvu": "<CVU de 22 dígitos>",
"accountInfo": {
"accountHolderName": "<titular de la cuenta de comercio>",
"accountHolderTaxId": "<CUIT del titular>",
"bankName": "<banco>"
},
"paymentRequests": [
{ "referenceId": "cuota-2026-10-001", "state": "pending" },
{ "referenceId": "cuota-2026-10-002", "state": "pending" }
]
}paymentRequests sigue el orden del request; el detalle se consulta con GET.
Ver las respuestas del bulk
| Código | Cuándo |
|---|---|
| 201 | Se crearon todos: guardá batchId. |
| 400 | Array vacío, más de 100 ítems o un campo fuera de contrato. |
| 422 | errors: [{ index, referenceId, reason }] con todos los ítems que fallaron: corregilos y reenviá el lote. |
| 429 | El lote no entra entero en el tope de mensajes de WhatsApp: no se crea nada. Consultá los límites. |
Con 400, 422 o 429 no se crea nada. Algunos reason, en inglés: Duplicate referenceId within the batch, The referenceId already exists for this integration, The taxDocument does not resolve to a valid CUIL y Duplicate payer within the batch: ....
sendWhatsappPaymentConfirmation vale para todo el lote y, si los ítems difieren, gana false. Los canales de aviso, al revés: si un ítem activa WhatsApp o email, queda activo para el lote.
Cobro de checkout
Un cobro type: "checkout" se paga desde el widget: consultá el cobro de checkout.