{"openapi":"3.1.0","info":{"title":"Talo Partner Hub API","version":"1.0.0","description":"Pagos por transferencia (ARS, CVU por pago) sobre una cuenta Talo Pay. Las keys tph_test_ operan en sandbox; las tph_live_, en producción."},"servers":[{"url":"https://talopartnerhub.vercel.app"}],"security":[{"bearer":[]}],"tags":[{"name":"Cuenta"},{"name":"Pagos"},{"name":"Checkout"},{"name":"Sandbox"},{"name":"Movimientos"},{"name":"Eventos"},{"name":"Keys"}],"paths":{"/api/v1/account":{"get":{"operationId":"listAccount","tags":["Cuenta"],"summary":"Cuenta Talo conectada: estado de activación y, cuando Talo los informa, prefijo de alias y vencimiento de pagos.","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"operationId":"updateAccount","tags":["Cuenta"],"summary":"Configura la cuenta. Solo cambian los campos enviados.","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"alias_prefix":{"type":"string","description":"Hasta 8 caracteres: minúsculas, números y guiones bajos."},"cancellation_period_minutes":{"type":"number","description":"Vencimiento de los pagos nuevos, de 5 a 20160 minutos."},"automatic_cancellation":{"type":"boolean","description":"Cancela solos los pagos vencidos."}},"required":[]}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"operationId":"deleteAccount","tags":["Cuenta"],"summary":"Desconecta la cuenta del hub, todo junto: borra la copia de la autorización de Talo, revoca todas las keys, desactiva los webhooks y cierra las sesiones del dashboard.","description":"Los pagos y la plata siguen en Talo, y el hub conserva su registro de pagos y eventos pasados. Para volver, autorizá de nuevo (npx talo-hub login). Es para la persona dueña de la cuenta: un agente no debería llamarlo sin que se lo pida.","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/payments":{"post":{"operationId":"createPayments","tags":["Pagos"],"summary":"Crea un pago por transferencia y devuelve el CVU y el alias para pagarlo.","description":"Repetir el mismo external_id devuelve el pago existente: los reintentos nunca cobran dos veces. La respuesta trae payment_url (la página de Talo del pago) y checkout_token, un token de solo lectura de ese pago para el widget (ver Checkout).","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"amount":{"type":"number","description":"Monto en ARS."},"external_id":{"type":"string","description":"Tu ID de orden. Hace seguros los reintentos."},"motive":{"type":"string","description":"Concepto que ve el comprador."},"redirect_url":{"type":"string","description":"Adónde vuelve el comprador desde la página de pago de Talo."},"client_data":{"type":"object","description":"first_name, last_name, email, phone, dni, cuit."}},"required":["amount"]}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Payment"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"get":{"operationId":"listPayments","tags":["Pagos"],"summary":"Pagos de un período (por defecto, los últimos 30 días).","description":"Talo no les deja listar pagos a las integraciones de partners: entonces el hub devuelve los que se crearon a través de él, con el último estado que registró, y `source: \"hub\"` (con `source: \"talo\"`, la lista viene de Talo). GET /api/v1/payments/{id} trae el detalle completo.","parameters":[{"name":"from","in":"query","required":false,"description":"Fecha ISO 8601.","schema":{"type":"string"}},{"name":"to","in":"query","required":false,"description":"Fecha ISO 8601.","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"from":{"type":"string"},"to":{"type":"string"},"source":{"type":"string","enum":["talo","hub"],"description":"hub: Talo didn't let the partner list payments, so these are the ones created through the hub, with the status it last recorded."},"payments":{"type":"array","items":{"$ref":"#/components/schemas/Payment"}}}}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/payments/{id}":{"get":{"operationId":"getPayments","tags":["Pagos"],"summary":"Estado, montos pagados y reembolsados, y reembolsos de un pago.","description":"paid y refunded son números (0 si no hay). refunds: [{ id, status: PENDING|SUCCESS|FAILED, type: FULL|PARTIAL, amount, currency, created_at }]. Leer un pago también pone al día sus eventos y trae un checkout_token nuevo (15 días).","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Payment"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/payments/{id}/price":{"put":{"operationId":"updatePaymentsPrice","tags":["Pagos"],"summary":"Cambia el monto. Talo recalcula el estado de un pago ya pagado.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"amount":{"type":"number","description":"Nuevo monto en ARS."}},"required":["amount"]}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Payment"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/payments/{id}/expiration":{"put":{"operationId":"updatePaymentsExpiration","tags":["Pagos"],"summary":"Extiende el vencimiento de un pago PENDING.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"expires_at":{"type":"string","description":"Fecha ISO 8601."}},"required":["expires_at"]}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Payment"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/payments/{id}/refunds":{"post":{"operationId":"createPaymentsRefunds","tags":["Pagos"],"summary":"Reembolsa un pago, total o parcial. Asincrónico: empieza PENDING.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"amount":{"type":"number","description":"ARS para un reembolso parcial. Sin amount, reembolso total."}},"required":[]}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Payment"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/payment-links":{"post":{"operationId":"createPaymentLinks","tags":["Checkout"],"summary":"Crea un link de pago reutilizable (/l/<id>): cada comprador que toca Pagar recibe un pago nuevo y va a la página de Talo con el CVU y el alias.","description":"Mandá amount (precio fijo) o min_amount y max_amount (el comprador escribe el monto). Devuelve url y qr_url. Sus pagos llevan external_id link_<id>_<al azar> (el id tiene 12 letras y números: external_id.slice(5, 17)) y motive = title, y el pedido se entrega con el webhook firmado, como cualquier pago. Hasta 20 pagos por hora desde una misma red (IP) por link, y un freno de 200 por link cada 10 minutos; quien vuelve al link recupera el pago que ya había empezado (también si transfirió de menos), y eso no cuenta.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","description":"Qué se paga, de 1 a 80 caracteres. Lo ve el comprador y es el motive de cada pago."},"description":{"type":"string","description":"Hasta 280 caracteres."},"amount":{"type":"number","description":"Precio fijo en ARS: positivo, hasta 2 decimales y 100.000.000."},"min_amount":{"type":"number","description":"Con max_amount y sin amount: el comprador escribe el monto, dentro de ese rango."},"max_amount":{"type":"number","description":"El monto más alto que puede escribir el comprador."},"redirect_url":{"type":"string","description":"URL https adonde la página de Talo devuelve al comprador (http solo para localhost)."}},"required":["title"]}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaymentLink"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"get":{"operationId":"listPaymentLinks","tags":["Checkout"],"summary":"Tus links de pago, del más nuevo al más viejo (hasta 100), con los desactivados (active: false).","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"payment_links":{"type":"array","items":{"$ref":"#/components/schemas/PaymentLink"}}}}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/payment-links/{id}":{"get":{"operationId":"getPaymentLinks","tags":["Checkout"],"summary":"Un link de pago y los pagos que se crearon con él: payments [{ id, status, amount, external_id, created_at }], del más nuevo al más viejo.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/PaymentLink"},{"type":"object","properties":{"payments":{"type":"array","description":"The payments buyers started with the link, newest first (up to 100).","items":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string"},"amount":{"type":"number"},"external_id":{"type":"string"},"created_at":{"type":"string","format":"date-time"}}}}}}]}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"operationId":"deletePaymentLinks","tags":["Checkout"],"summary":"Desactiva un link de pago para siempre. Los pagos que ya empezaron con él se pueden seguir pagando.","description":"No se puede reactivar: creá otro. Un link que ya estaba desactivado responde 410 link_disabled.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"active":{"type":"boolean","const":false}}}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/public/payments/{id}":{"get":{"operationId":"getPublicPayments","tags":["Checkout"],"summary":"La vista pública de un pago, para el widget o tu propia página: estado, monto, pagado, CVU, alias, vencimiento y payment_url.","description":"Sin API key: la autoriza el checkout_token del pago (lo devuelven POST /api/v1/payments y GET /api/v1/payments/{id}), que solo sirve para leer ese pago y vence a los 15 días. Cualquier origen puede llamarla (CORS *) y el CDN guarda cada respuesta 3 segundos. Un token inválido, vencido o de otro pago, una cuenta desconectada y un pago que no existe responden lo mismo: 404 not_found.","security":[],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"token","in":"query","required":true,"description":"El checkout_token del pago (ct_…).","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicPayment"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/sandbox/transfers":{"post":{"operationId":"createSandboxTransfers","tags":["Sandbox"],"summary":"Simula la transferencia del comprador a un pago de sandbox.","description":"Con menos monto probás UNDERPAID; con más, OVERPAID. Dispara los mismos eventos que una transferencia real. Solo con keys de sandbox (tph_test_).","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"payment_id":{"type":"string","description":"El pago a pagar."},"amount":{"type":"number","description":"ARS. Por defecto, el monto del pago."}},"required":["payment_id"]}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/balance":{"get":{"operationId":"listBalance","tags":["Movimientos"],"summary":"Saldo de la cuenta.","description":"Talo todavía no lo habilita para integraciones de partner: hoy responde talo_partner_unsupported (501).","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/transactions":{"get":{"operationId":"listTransactions","tags":["Movimientos"],"summary":"Transferencias entrantes y salientes, paginadas.","description":"Talo todavía no lo habilita para integraciones de partner: hoy responde talo_partner_unsupported (501). El estado de cada cobro siempre está en /api/v1/payments.","parameters":[{"name":"from","in":"query","required":false,"description":"Fecha ISO 8601.","schema":{"type":"string"}},{"name":"to","in":"query","required":false,"description":"Fecha ISO 8601.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Hasta 200.","schema":{"type":"number"}},{"name":"cursor","in":"query","required":false,"description":"El next_cursor de la página anterior.","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/events":{"get":{"operationId":"listEvents","tags":["Eventos"],"summary":"Eventos de la cuenta, para escuchar sin exponer un servidor.","description":"Con after: los posteriores a ese ID, del más viejo al más nuevo (seguí con next_after). Con recent: los últimos n, del más nuevo al más viejo.","parameters":[{"name":"after","in":"query","required":false,"description":"Devuelve los eventos posteriores a este ID.","schema":{"type":"number"}},{"name":"recent","in":"query","required":false,"description":"Los últimos n eventos (1 a 200).","schema":{"type":"number"}},{"name":"limit","in":"query","required":false,"description":"Hasta 200.","schema":{"type":"number"}},{"name":"payment_id","in":"query","required":false,"description":"Solo los eventos de ese cobro.","schema":{"type":"string"}},{"name":"type","in":"query","required":false,"description":"Solo ese tipo, p. ej. payment.paid.","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/Event"}},"next_after":{"type":"integer"}}}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/webhook-endpoints":{"get":{"operationId":"listWebhookEndpoints","tags":["Eventos"],"summary":"Tus webhooks.","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"createWebhookEndpoints","tags":["Eventos"],"summary":"Registra un webhook https. Devuelve el secreto de firma una sola vez.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","description":"URL https que recibe los eventos."}},"required":["url"]}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/webhook-endpoints/{id}":{"delete":{"operationId":"deleteWebhookEndpoints","tags":["Eventos"],"summary":"Da de baja un webhook.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/webhook-endpoints/{id}/test":{"post":{"operationId":"createWebhookEndpointsTest","tags":["Eventos"],"summary":"Manda ya un evento webhook.test firmado y dice si tu endpoint respondió 2xx.","description":"No mueve plata: sirve en sandbox y en producción para verificar tu handler.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/readiness":{"get":{"operationId":"listReadiness","tags":["Cuenta"],"summary":"Checklist para pasar a producción: qué está hecho y cómo resolver lo que falta.","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/api-keys":{"get":{"operationId":"listApiKeys","tags":["Keys"],"summary":"Tus API keys (solo el prefijo).","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"createApiKeys","tags":["Keys"],"summary":"Crea una API key. Se muestra una sola vez.","description":"Solo con una key full (o desde el dashboard). La nueva puede tener cualquier scope y es charge si no pedís otro.","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Para reconocerla después."},"scope":{"type":"string","description":"read, charge o full (por defecto charge)."}},"required":[]}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/api-keys/{id}":{"delete":{"operationId":"deleteApiKeys","tags":["Keys"],"summary":"Revoca una API key.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"components":{"securitySchemes":{"bearer":{"type":"http","scheme":"bearer","description":"API key del hub: tph_test_… o tph_live_…"}},"schemas":{"Payment":{"type":"object","required":["id","status","amount","currency","paid","refunded","refunds"],"properties":{"id":{"type":"string"},"status":{"type":"string","enum":["PENDING","SUCCESS","OVERPAID","UNDERPAID","EXPIRED"]},"external_id":{"type":"string"},"amount":{"type":"number"},"currency":{"type":"string"},"cvu":{"type":"string"},"alias":{"type":"string"},"paid":{"type":"number"},"refunded":{"type":"number"},"refunds":{"type":"array","items":{"type":"object","properties":{"id":{"type":["string","null"]},"status":{"type":["string","null"],"enum":["PENDING","SUCCESS","FAILED",null]},"type":{"type":["string","null"],"enum":["FULL","PARTIAL",null]},"amount":{"type":["number","null"]},"currency":{"type":"string"},"created_at":{"type":["string","null"]}}}},"expires_at":{"type":"string","format":"date-time"},"created_at":{"type":"string","format":"date-time"},"motive":{"type":"string"},"payment_url":{"type":"string","description":"Talo's hosted page for the payment, when Talo provides one."},"checkout_token":{"type":"string","description":"Only in the answers to POST /api/v1/payments and GET /api/v1/payments/{id} (not in lists or webhook events): a read-only token (ct_…) for this payment's public view, GET /api/public/payments/{id}, valid 15 days from when it was issued. Safe to hand to the browser, for the <talo-checkout> widget."}}},"PublicPayment":{"type":"object","description":"What a buyer needs to pay one payment and follow it. Every field is always present; missing values are null.","required":["id","status","amount","currency","paid","cvu","alias","expires_at","motive","payment_url","environment"],"properties":{"id":{"type":"string"},"status":{"type":"string","enum":["PENDING","SUCCESS","OVERPAID","UNDERPAID","EXPIRED"]},"amount":{"type":["number","null"]},"currency":{"type":"string"},"paid":{"type":"number"},"cvu":{"type":["string","null"]},"alias":{"type":["string","null"]},"expires_at":{"type":["string","null"],"format":"date-time"},"motive":{"type":["string","null"]},"payment_url":{"type":["string","null"]},"environment":{"type":"string","enum":["sandbox","production"]}}},"PaymentLink":{"type":"object","description":"A reusable payment link. Fixed price: amount is set and min_amount/max_amount are null; open amount: the reverse.","required":["id","url","qr_url","environment","title","description","amount","min_amount","max_amount","redirect_url","active","created_at"],"properties":{"id":{"type":"string","description":"12 letters and digits; the link is /l/<id>, and its payments' external_id is link_<id>_<random>."},"url":{"type":"string","format":"uri","description":"The page to share: /l/<id>."},"qr_url":{"type":"string","format":"uri","description":"An SVG QR code of url: /l/<id>/qr.svg."},"environment":{"type":"string","enum":["sandbox","production"]},"title":{"type":"string"},"description":{"type":["string","null"]},"amount":{"type":["number","null"]},"min_amount":{"type":["number","null"]},"max_amount":{"type":["number","null"]},"redirect_url":{"type":["string","null"]},"active":{"type":"boolean","description":"false once disabled; a disabled link stays disabled."},"created_at":{"type":"string","format":"date-time"}}},"Event":{"type":"object","required":["id","type","created_at","data"],"properties":{"id":{"type":"integer"},"type":{"type":"string"},"created_at":{"type":"string","format":"date-time"},"data":{"type":"object","properties":{"payment":{"$ref":"#/components/schemas/Payment"},"previous_status":{"type":["string","null"]}}}}},"Error":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"object"}},"required":["code","message"]}}}}}}