Metadata-Version: 2.4
Name: vitrin
Version: 0.2.0
Summary: SDK oficial Python para a API da Vitrin Digital
Project-URL: Homepage, https://vitrin.digital
Project-URL: Documentation, https://vitrin.digital/docs/integracao
Project-URL: Repository, https://github.com/vitrindigital/vitrin
Author: Vitrin Digital
License-Expression: MIT
Keywords: boleto,checkout,pagamentos,pix,vitrin,vitrin-digital
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Office/Business :: Financial
Requires-Python: >=3.10
Requires-Dist: requests>=2.31
Provides-Extra: dev
Requires-Dist: mypy>=1.10; extra == 'dev'
Requires-Dist: pytest-mock>=3.12; extra == 'dev'
Requires-Dist: pytest>=8; extra == 'dev'
Requires-Dist: responses>=0.25; extra == 'dev'
Requires-Dist: ruff>=0.7; extra == 'dev'
Description-Content-Type: text/markdown

# vitrin (Python)

SDK oficial Python para a [API da Vitrin Digital](https://api.vitrin.digital).

```bash
pip install vitrin
```

> **Python 3.10+** requerido. Única dependência runtime: `requests`.

## Setup

```python
import os
from vitrin import Vitrin

vitrin = Vitrin(
    api_key=os.environ["VITRIN_API_KEY"],
    # opcionais:
    # base_url="https://api.vitrin.digital/api/v1",
    # timeout=30.0,
    # max_retries=3,
)
```

Use `vd_test_*` em desenvolvimento, `vd_live_*` em produção.

## Recursos

### Clientes

```python
customer = vitrin.customers.create(
    name="Maria Silva",
    email="maria@example.com",
    cpf_cnpj="12345678901",
)

vitrin.customers.list(page=1)
vitrin.customers.update(customer["id"], phone="11987654321")
vitrin.customers.delete(customer["id"])
```

### Cobranças

```python
charge = vitrin.charges.create(
    customer_id=customer["id"],
    amount=99.90,
    billing_type="PIX",
    description="Mensalidade abril",
    idempotency_key=f"mensalidade-{customer['id']}-2026-04",  # evita duplo-débito em retry
)

print(charge["pix_qr_code"])
print(charge["pix_copy_paste"])

# Reembolso parcial
vitrin.charges.refund(charge["id"], amount=50.0, pin="123456")
```

### Planos & Assinaturas

```python
plan = vitrin.plans.create(name="Pro Mensal", price=99.0, billing_cycle="monthly")

sub = vitrin.subscriptions.create(
    customer_id=customer["id"],
    plan_id=plan["id"],
    billing_type="CREDIT_CARD",
    credit_card_token="tok_xxx",
)

vitrin.subscriptions.cancel(sub["id"], pin="123456")
```

### Saldo & Recebíveis

```python
vitrin.balance.retrieve()
# → { "available": ..., "total": ..., "pending": ..., "withdrawal_fees": {...} }

vitrin.balance.scheduled(90)
# → cronograma 90d: PIX D+1, Boleto D+2, Cartão Nx D+30·n
```

## Webhooks

```python
from flask import Flask, request, abort
from vitrin import webhooks, VitrinError
import os

app = Flask(__name__)

@app.post("/webhooks/vitrin")
def handle_webhook():
    try:
        event = webhooks.construct_event(
            payload=request.get_data(),                          # body cru, NÃO parsed
            signature=request.headers.get("X-Vitrin-Signature"),
            timestamp=request.headers.get("X-Vitrin-Timestamp"),
            event_type=request.headers.get("X-Vitrin-Event"),
            event_id=request.headers.get("X-Vitrin-Event-Id"),
            secret=os.environ["VITRIN_WEBHOOK_SECRET"],
        )
        print(event.type, event.id, event.data)
        return "", 200
    except VitrinError as e:
        return str(e), 400
```

## Tratamento de erros

```python
from vitrin import (
    VitrinError, VitrinAuthError, VitrinValidationError,
    VitrinRateLimitError, VitrinNotFoundError, VitrinServerError,
)

try:
    vitrin.charges.create(...)
except VitrinValidationError as e:
    print("Campos inválidos:", e.field_errors)
except VitrinAuthError:
    print("Chave inválida ou sem permissão")
except VitrinRateLimitError:
    print("Aguarde antes de tentar de novo")
except VitrinError as e:
    print(f"Erro Vitrin: {e.status_code} {e.request_id} {e.message}")
```

Retry automático em **429** e **5xx** com backoff exponencial (default: 3 tentativas). 4xx (exceto 429) não são retentados.

## Idempotência

Inclua `idempotency_key` em POSTs sensíveis. Se o request chegar duas vezes (retry de rede, deploy etc), a Vitrin reconhece pela chave e devolve a mesma resposta — sem cobrar duas vezes.

```python
vitrin.charges.create(
    customer_id="cus_1",
    amount=100,
    billing_type="PIX",
    idempotency_key=f"pedido-{order_id}",  # único por pedido
)
```

## Acesso bruto

```python
data = vitrin.request("/some/path/", method="POST", body={"foo": "bar"})
```

## Licença

MIT
