Skip to main content

PagoTIC SDK para Python

Paquete no oficial. Este SDK es mantenido por la comunidad y no está afiliado, respaldado ni soportado por PagoTIC. Usá la API oficial bajo tu propia responsabilidad.

SDK en Python para integrar la pasarela de pagos PagoTIC (Pay per TIC). Incluye cliente sincrónico y asincrónico, autenticación OAuth2 automática, modelos tipados con Pydantic, pagos, distribución programada, importación masiva, suscripciones y utilidades para webhooks.

  • Python 3.10+
  • httpx + pydantic v2
  • Tipado completo (py.typed)
  • Tests con respx, lint con ruff, chequeo de tipos con mypy

Instalación

pip install pagotic-sdk

Con pipx para instalarlo aislado:

pipx install pagotic-sdk

Para generar códigos QR localmente (sin servicios externos) agregá el extra qr:

pip install "pagotic-sdk[qr]"
pipx install "pagotic-sdk[qr]"   # alternativa con pipx

Con Poetry:

poetry add pagotic-sdk
poetry add "pagotic-sdk[qr]"  # opcional, para QR local

También podés instalarlo desde el repositorio:

pip install "pagotic-sdk @ git+https://github.com/Alitux/pagotic-sdk.git"

Inicio rápido

from pagotic import PagoTIC

with PagoTIC() as sdk:
    payment = sdk.payments.create(
        {
            "external_transaction_id": "orden-123",
            "currency_id": "ARS",
            "details": [
                {
                    "external_reference": "item-1",
                    "concept_id": 920,
                    "concept_description": "Suscripción mensual",
                    "amount": 1500.50,
                }
            ],
            "payer": {
                "name": "Ana Pérez",
                "email": "ana@example.com",
                "identification": {
                    "type": "DNI_ARG",
                    "number": "12345678",
                    "country": "ARG",
                },
            },
            "notification_url": "https://example.com/webhooks/pagotic",
        }
    )

    print(payment.id, payment.status, payment.form_url)

Configuración

Las credenciales se pueden pasar al constructor o definir por entorno:

Variable Descripción
PAGOTIC_USERNAME Usuario de la API
PAGOTIC_PASSWORD Contraseña
PAGOTIC_CLIENT_ID Client ID de Keycloak
PAGOTIC_CLIENT_SECRET Client Secret de Keycloak
PAGOTIC_AUTH_URL Default: https://a.paypertic.com
PAGOTIC_API_URL Default: https://api.paypertic.com
PAGOTIC_REALM Default: entidades
PAGOTIC_TIMEOUT Timeout HTTP en segundos (default: 30)
PAGOTIC_MAX_RETRIES Reintentos en GET/HEAD (default: 2)
PAGOTIC_RETRY_BACKOFF Base del backoff exponencial (default: 0.25)
PAGOTIC_TOKEN_LEEWAY Margen de renovación del token (default: 30)

Las credenciales y URLs se normalizan automáticamente: se ignoran los espacios al inicio y al final, y un valor con solo espacios se considera ausente. En los ejemplos y tests de integración el .env se carga con override=True para que variables del sistema (por ejemplo USERNAME) no pisen las credenciales.

from pagotic import PagoTIC

sdk = PagoTIC(
    username="...",
    password="...",
    client_id="...",
    client_secret="...",
)

El token se solicita de forma lazy, se cachea según expires_in, se renueva con refresh_token y, ante un 401, se reintenta una vez. Los reintentos por red o 5xx/429 solo aplican a métodos idempotentes (GET/HEAD), nunca a la creación de pagos.

Pagos

Crear, obtener y cancelar

payment = sdk.payments.create({...})
same = sdk.payments.get(payment.id)
sdk.payments.cancel(payment.id, "Solicitado por el comercio")
sdk.payments.cancel_objection(payment.id, "Objeción resuelta")

Listar con filtros

result = sdk.payments.list(
    page=1,
    limit=20,
    sorts={"request_date": "descending"},
    filters=[
        {"field": "collector_id", "operation": "EQUAL", "value": "123"},
        {
            "field": "request_date",
            "operation": "GREATER_THAN_OR_EQUAL_TO",
            "value": "20250101T000000000-0300",
        },
    ],
)

La API exige combinaciones mínimas de filtros (por ejemplo collector_id + request_date). No uses BETWEEN: enviá dos filtros sobre el mismo campo. Para fechas podés usar format_filter_datetime.

Búsqueda legacy

sdk.payments.search({"payer_email": "ana@example.com", "status": "approved"})

Devoluciones, agrupaciones y cupones

refund = sdk.payments.refund(payment.id, {"reason": "Reintegro"})

grouped = sdk.payments.group([payment_a.id, payment_b.id])
sdk.payments.cancel_group(grouped.id, "Cancelación de la agrupación")

coupon = sdk.payments.create_coupon(payment, media_payment_id=97)  # 97 Rapipago, 98 Pago Fácil
print(coupon.payment_methods[0].coupon_number)

Medios de pago y presets

MediaPayment enumera los media_payment_id documentados. Podés combinar tarjetas de crédito, débito y QR en el checkout con presets:

from pagotic import MediaPayment, PaymentRequest, Presets

payment = sdk.payments.create(
    PaymentRequest(
        external_transaction_id="orden-125",
        currency_id="ARS",
        details=[{"external_reference": "a", "amount": 1500}],
        payer={"name": "Ana Pérez", "email": "ana@example.com"},
        presets=Presets(
            media_payment_ids=[
                *MediaPayment.cards(),  # crédito + débito
                MediaPayment.QR,
            ]
        ),
    )
)
print(payment.form_url)  # checkout filtrado a esos medios

presets solo filtra las opciones del checkout: no cobra en el momento. Para habilitar el QR interoperable usá MediaPayment.QR (85). También podés agrupar por tipo: MediaPayment.credit_cards(), MediaPayment.debit_cards(), MediaPayment.cards() y MediaPayment.coupons().

Cuando se cobra directo con tarjeta (type="online" + payment_methods), el QR no participa del flujo. Los IDs deben estar habilitados para el comercio.

QR

El pago se crea con QR como medio (por ejemplo, presets con MediaPayment.QR). Una vez creado, raw_qr aparece en payment_methods[] al consultar sdk.payments.get(id) o en el webhook:

from pagotic import save_qr

payment = sdk.payments.get(payment_id)
if payment.raw_qr:
    path = save_qr(payment.raw_qr, "qr.png", scale=6)
    print(f"QR guardado en {path}")

El QR se genera localmente con segno (Python puro, sin Pillow ni servicios externos). Para eso instalá el extra:

pip install "pagotic-sdk[qr]"

También están render_qr_png y render_qr_svg para obtener los bytes o el SVG en memoria. Si preferís delegar la imagen a un servicio externo, seguí usando build_qr_image_url.

Cada QR es de un solo uso: una vez pagado queda invalidado.

Distribución programada

Al crear un pago se puede repartir el monto entre varias cuentas CBU:

from pagotic import Distribution, PaymentRequest

payment = sdk.payments.create(
    PaymentRequest(
        external_transaction_id="orden-124",
        currency_id="ARS",
        details=[
            {"external_reference": "a", "amount": 800},
            {"external_reference": "b", "amount": 200},
        ],
        payer={"name": "Ana Pérez", "email": "ana@example.com"},
        distribution=Distribution.scheduled(
            [
                {
                    "cbu": "0000000000000000000000",
                    "cuit": "20123456789",
                    "name": "Proveedor A",
                    "amount": 800,
                },
                {
                    "cbu": "1111111111111111111111",
                    "cuit": "20987654321",
                    "name": "Proveedor B",
                    "amount": 200,
                },
            ]
        ),
    )
)

Validación obligatoria: la suma de distribution.details[].amount debe ser exactamente igual a la suma de details[].amount. Si no coincide, el SDK lanza PagoTICValidationError y no envía la request.

Importación masiva

El CSV debe estar sin encabezados y tener como máximo 40.000 registros. Al menos uno de los flags debe ser true; si match_identification=True, los otros dos deben ser false.

summary = sdk.imports.preimport("pagos.csv", match_payer=True)
sdk.imports.get(summary.import_id)
details = sdk.imports.details(summary.import_id)
sdk.imports.approve(summary.import_id)
# o bien:
sdk.imports.cancel(summary.import_id, "Importación duplicada")

También están disponibles las rutas legacy verify_legacy, approve_legacy y cancel_legacy.

Suscripciones (experimental)

Esta funcionalidad solo aparece en la colección Postman, no en la documentación PDF. La API podría cambiarla sin previo aviso.

subscription = sdk.subscriptions.create(
    {
        "currency_id": "ARS",
        "due_day": "30",
        "recurrence": "monthly",
        "detail": {
            "external_reference": "plan-1",
            "concept_description": "Plan mensual",
            "amount": 5000,
        },
        "payment_method": {
            "number": "4111111111111111",
            "holder": {
                "name": "Ana Pérez",
                "identification": {"type": "DNI_ARG", "number": "12345678", "country": "ARG"},
            },
        },
        "payer": {"name": "Ana Pérez", "email": "ana@example.com"},
    }
)
sdk.subscriptions.list()
sdk.subscriptions.search({"payer_email": "ana@example.com"})
sdk.subscriptions.cancel(subscription.id, "Baja solicitada")

Webhooks

PagoTIC envía el JSON del pago a notification_url. La documentación no define firma ni secreto, así que el SDK solo parsea el payload:

from fastapi import FastAPI, Request
from pagotic import parse_notification

app = FastAPI()


@app.post("/webhooks/pagotic")
async def pagotic_webhook(request: Request):
    payment = parse_notification(await request.body())
    if payment.status == "approved":
        ...
    return {"ok": True}

Errores

from pagotic import (
    PagoTICAPIError,
    PagoTICAuthError,
    PagoTICConnectionError,
    PagoTICValidationError,
)

try:
    sdk.payments.get("no-existe")
except PagoTICAPIError as exc:
    print(exc.status_code, exc.code, exc.extended_code, exc.message, exc.payload)

Jerarquía: PagoTICError → PagoTICConfigError, PagoTICValidationError, PagoTICConnectionError, PagoTICAPIError, PagoTICAuthError.

Cliente asincrónico

from pagotic import AsyncPagoTIC

async with AsyncPagoTIC() as sdk:
    payment = await sdk.payments.create({...})
    await sdk.payments.cancel(payment.id, "Cancelado")

Desarrollo

poetry install
make lint        # ruff check + format --check
make typecheck   # mypy
make test        # pytest
make test-cov    # pytest + cobertura
make build       # wheel + sdist

Los tests unitarios usan respx y no tocan la red. Los tests de integración están marcados con integration y se saltean si no hay credenciales:

cp .env.example .env   # completá tus credenciales
PAGOTIC_RUN_INTEGRATION=1 poetry run pytest -m integration

.env está ignorado por git; nunca commitees credenciales.

Mantenimiento

Mantenido por Alitux — alitux@disroot.org.

Licencia

GNU General Public License v3.0 o posterior. Ver LICENSE.

Metadata

Release files for pagotic-sdk 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pagotic-sdk 0.1.1
File Size Uploaded
pagotic_sdk-0.1.1.tar.gz 39.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for pagotic-sdk 0.1.1
File Interpreter ABI Platform
pagotic_sdk-0.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 82.9 kB

Release files / pagotic_sdk-0.1.1.tar.gz

Download URL pagotic_sdk-0.1.1.tar.gz
Size 39.4 kB
Tags Source
SHA-256 checksum
How to use checksums
1ac69bd2e1c061ceedda5758c38376fa9b0e85b6a12398cf46da9f32f699f7c9
BLAKE2b-256 checksum
How to use checksums
fb6912e8d9c8e6a12102c6a948ee8599c43aec17c923b3896b95ea63aab0978e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 19, 2026.

Transparency log

Release files / pagotic_sdk-0.1.1-py3-none-any.whl

Download URL pagotic_sdk-0.1.1-py3-none-any.whl
Size 43.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
503659d24f06375b3e908feeb86316cf92c800f83ae7de161e72f27ac37a5ce1
BLAKE2b-256 checksum
How to use checksums
a4860c97dde59ce01fc3989f98a7b001ba0a82c2bc0590596649fcfd994fb18b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 19, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page