vitrin (Python)
SDK oficial Python para a API da Vitrin Digital.
pip install vitrin
Python 3.10+ requerido. Única dependência runtime:
requests.
Setup
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.
Organizações LLC (US)
Se a org é uma US LLC (entity_type == "llc"), os valores são em USD
(campo currency nas transações); os métodos default são cartão e Pix
cross-border (o cliente paga em BRL, a LLC recebe em USD). A liquidação é
automática: os endpoints de saldo/recebíveis/transferências retornam
{ "auto_payout": true } em vez de saldo retido (não há saque/antecipação
manual; o cronograma "PIX D+1 / Boleto D+2 / Cartão Nx D+30" abaixo é só para
CNPJ). O onboarding inclui verificação de identidade (KYC). Veja
docs/api/onboarding-llc.md e docs/api/differences-cnpj-llc.md.
Recursos
Clientes
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
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
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
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
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
from vitrin import (
VitrinError, VitrinAuthError, VitrinValidationError, VitrinRefusedError,
VitrinRateLimitError, VitrinNotFoundError, VitrinServerError,
)
try:
vitrin.charges.create(...)
except VitrinRefusedError as e:
# A cobrança CHEGOU ao emissor e ele negou.
print("Recusado:", e.code, e.customer_message)
except VitrinValidationError as e:
# A cobrança NÃO saiu daqui — o payload foi rejeitado.
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.
Recusa não é erro de validação
A API usa 422 para duas situações opostas, e o SDK as separa em classes diferentes:
| Classe | O que aconteceu | O que fazer |
|---|---|---|
VitrinValidationError |
O payload foi rejeitado. Nada foi enviado ao banco. | Corrigir os campos (field_errors) e repetir. |
VitrinRefusedError |
A cobrança chegou ao emissor e ele negou. | Exibir customer_message; oferecer retry só se retryable. |
O discriminador é o código de retorno no corpo (return_code / abecs_code): ele só existe porque houve resposta de autorização.
except VitrinRefusedError as e:
mostrar_erro(e.customer_message) # texto pronto, em PT-BR
if e.retryable:
oferecer_nova_tentativa() # ex.: 51 saldo, 91 emissor fora do ar
else:
oferecer_outro_cartao() # ex.: 82 negada — o mesmo cartão vai negar de novo
log.info("recusa %s tx=%s", e.code, e.transaction_id)
transaction_id aponta para a Transaction failed que registra a tentativa — ela também aparece em GET /transactions/?status=failed e no painel.
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.
Vale em charges.create() e charges.create_with_saved_card(). A chave é escopada por organização (a sua nunca colide com a de outro lojista) e aceita até 128 caracteres.
Use um identificador seu e estável — número do pedido, id do carrinho. A proteção vem de a chave se repetir no retry; um UUID novo a cada tentativa não protege de nada.
vitrin.charges.create(
customer_id="cus_1",
amount=100,
billing_type="PIX",
idempotency_key=f"pedido-{order_id}", # único por pedido
)
Acesso bruto
data = vitrin.request("/some/path/", method="POST", body={"foo": "bar"})
Licença
MIT
Release files for vitrin 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| vitrin-0.3.0.tar.gz | 15.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| vitrin-0.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 31.0 kB
Release files / vitrin-0.3.0.tar.gz
| Download URL | vitrin-0.3.0.tar.gz |
|---|---|
| Size | 15.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
8991e680c33d5828b1d9d50a2c5dfde9e749b9c97fd87b78e21230f53398fa06
|
|
BLAKE2b-256 checksum How to use checksums |
92e2717b7500a7b389f1223122ee3be67e427d2168c4c3333ec77b24c92772fe
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.9.6
|
Release files / vitrin-0.3.0-py3-none-any.whl
| Download URL | vitrin-0.3.0-py3-none-any.whl |
|---|---|
| Size | 15.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
dd91830508d7ff19dc61623548282566b8dce985dd88192c1fb90329551833d3
|
|
BLAKE2b-256 checksum How to use checksums |
070d440b41915d3fd32f3da5934f1cf0b6eeaccb7b96cf3a25f36c27b904817e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.9.6
|