Skip to main content

SDK oficial da FluvPay para Python. Pagamentos PIX, saques, transferencias internas e verificacao de webhooks.

Project description

FluvPay Python

SDK oficial da FluvPay para Python. Cobre cobranças PIX, saques, transferências internas e verificação de webhooks, com tipagem forte e erros idiomáticos. A interface é declarativa e estável, adequada tanto a integrações conduzidas por desenvolvedores quanto a agentes e sistemas de IA que consomem a documentação para integrar.

  • Requer Python 3.9 ou superior.
  • Cliente HTTP construído sobre httpx.
  • Retentativas automáticas em operações seguras, Idempotency-Key gerada automaticamente e erros tipados.

Instalação

O pacote está publicado no PyPI:

pip install fluvpay

A instalação direta a partir do repositório também é suportada:

pip install "git+https://github.com/fluvpay/fluvpay-python.git"

Uma referência marcada com tag pode ser fixada:

pip install "git+https://github.com/fluvpay/fluvpay-python.git@v1.0.0"

Início rápido

from fluvpay import FluvPay, FluvPayValidationError, verify_signature

client = FluvPay("fluv_test_sua_chave_de_teste")

try:
    charge = client.charges.create(
        {
            "amount_cents": 5000,
            "description": "Pedido 123",
            "customer": {"name": "Maria", "email": "maria@example.com"},
            "metadata": {"pedido_id": "123"},
        }
    )
except FluvPayValidationError as err:
    print("Dados inválidos:", err.code, err.message)
    for d in err.details:
        print(" -", d.field, d.message)
    raise

print("Cobrança criada:", charge.id, charge.status)
print("Copia e cola PIX:", charge.pix_copy_paste)

mesma = client.charges.retrieve(charge.id)
print("Status atual:", mesma.status)

pagina = client.charges.list(page=1, per_page=20, status="paid")
print(f"Página {pagina.page} de {pagina.total} cobranças, há mais? {pagina.has_next}")
for item in pagina:
    print(" -", item.id, item.amount_cents, item.status)


def handle_webhook(raw_body: bytes, headers: dict):
    event = verify_signature(
        payload=raw_body,
        signature_header=headers["X-FluvPay-Signature"],
        timestamp=headers["X-FluvPay-Timestamp"],
        secret="whsec_seu_segredo_do_webhook",
        event_type=headers.get("X-FluvPay-Event"),
        delivery_id=headers.get("X-FluvPay-Delivery-Id"),
        tolerance_seconds=300,
    )
    if event.type == "charge.paid":
        print("Cobrança paga:", event.data.get("id"))

Valores monetários são expressos em centavos. A verificação de webhook usa o corpo cru da requisição (bytes), nunca o JSON re-serializado.

Autenticação

A autenticação usa a API key passada ao construtor. O ambiente é determinado pelo prefixo da chave: fluv_live_ seleciona produção e fluv_test_ seleciona o sandbox.

from fluvpay import FluvPay

client = FluvPay("fluv_live_sua_chave_aqui")

A base URL padrão é https://api.fluvpay.com/api/v1 e pode ser sobrescrita com o parâmetro base_url.

Referência de recursos

Cada recurso corresponde a um conjunto de rotas do contrato da API.

Charges (cobranças PIX):

client.charges.create(params, idempotency_key=None)   # POST /charges/
client.charges.retrieve(charge_id)                    # GET  /charges/{id}
client.charges.list(page=, per_page=, sort=, status=) # GET  /charges/

Transactions (extrato):

client.transactions.list(page=, per_page=, sort=)     # GET /transactions/
client.transactions.retrieve(tx_id)                   # GET /transactions/{id}

Withdrawals (saques PIX, disponíveis apenas em produção):

client.withdrawals.create(params, idempotency_key=None)  # POST /withdrawals/
client.withdrawals.list(limit=, offset=, status=)        # GET  /withdrawals/
client.withdrawals.retrieve(withdrawal_id)               # GET  /withdrawals/{id}

Internal Transfers (transferências entre contas FluvPay, disponíveis apenas em produção):

client.internal_transfers.create(params, idempotency_key=None)  # POST /internal-transfers/
client.internal_transfers.list(direction=, limit=, offset=)     # GET  /internal-transfers/
client.internal_transfers.retrieve(transfer_id)                 # GET  /internal-transfers/{id}

Sandbox (disponível apenas com chave fluv_test_):

client.sandbox.reset()       # POST /test/reset
client.sandbox.scenarios()   # GET  /test/scenarios

Criação de cobrança: campos aceitos

charges.create aceita exatamente os campos do contrato. Os campos currency e method não são aceitos e produzem resposta 422.

Campo Tipo Observação
amount_cents int, obrigatório 100 a 100000 (R$ 1,00 a R$ 1.000,00)
description str até 500 caracteres
customer dict {name?, email?, document?, phone?}
expires_in_seconds int 60 a 604800
affiliate_code str 4 a 24 caracteres
split_rule_id str 20 a 32 caracteres
pass_fee_to_payer bool padrão True
metadata dict objeto livre

Os estados possíveis de uma cobrança são pending, paid, expired, cancelled e refunded.

Paginação

Existem dois envelopes de paginação, expostos como objetos de página tipados, iteráveis e compatíveis com len():

  • charges.list e transactions.list retornam page, per_page, total, has_next e has_prev.
  • withdrawals.list e internal_transfers.list retornam limit, offset e total.
page = client.withdrawals.list(limit=10, offset=0)
print(page.limit, page.offset, page.total)
for w in page:
    print(w.id, w.status, w.net_cents)

Webhooks

A FluvPay assina cada entrega. O header X-FluvPay-Signature carrega o valor v1=<hex>, calculado da seguinte forma:

hex = HMAC_SHA256(secret, "{timestamp}." + rawBody)

secret é o valor whsec_... exibido na criação do webhook, timestamp provém do header X-FluvPay-Timestamp e rawBody são os bytes crus do corpo. A verificação deve usar o corpo cru, nunca o JSON re-serializado.

from fluvpay import verify_signature, FluvPaySignatureVerificationError

try:
    event = verify_signature(
        payload=raw_body,
        signature_header=request.headers["X-FluvPay-Signature"],
        timestamp=request.headers["X-FluvPay-Timestamp"],
        secret="whsec_...",
        tolerance_seconds=300,
    )
except FluvPaySignatureVerificationError:
    return "assinatura inválida", 400

Os eventos disponíveis são charge.created, charge.paid, charge.expired, charge.cancelled, charge.refunded, payout.created, payout.completed e payout.failed.

Erros

Todas as exceções herdam de FluvPayError e expõem os atributos code, message, details, trace_id e status_code. O tipo da exceção é determinado pelo status HTTP da resposta.

Status Exceção
400 / 422 FluvPayValidationError
401 FluvPayAuthenticationError
403 FluvPayPermissionError
404 FluvPayNotFoundError
409 FluvPayConflictError
429 FluvPayRateLimitError (atributo retry_after)
5xx FluvPayServerError
rede / timeout FluvPayConnectionError
from fluvpay import FluvPayRateLimitError

try:
    client.charges.list()
except FluvPayRateLimitError as err:
    print("Rate limit. Tente novamente em", err.retry_after, "segundos.")

Idempotência

As operações de escrita (charges.create, withdrawals.create, internal_transfers.create) usam o header Idempotency-Key. Quando a chave não é informada, o SDK gera um UUIDv4. O reenvio da mesma chave retorna a resposta original. O reuso da mesma chave com um payload diferente resulta em FluvPayConflictError com código IDEMPOTENCY_CONFLICT.

chave = FluvPay.new_idempotency_key()
client.charges.create({"amount_cents": 5000}, idempotency_key=chave)

Retentativas

O SDK realiza até 2 retentativas por padrão, com backoff exponencial e jitter, restritas a operações seguras: requisições GET e POSTs que carregam Idempotency-Key. As retentativas ocorrem apenas em respostas 429, respostas 5xx e falhas de conexão. Em respostas 429, o header Retry-After é respeitado.

client = FluvPay("fluv_live_...", max_retries=4)   # aumentar o limite
client = FluvPay("fluv_live_...", max_retries=0)   # desativar

Desenvolvimento

python -m pip install -e ".[dev]"
python -m pytest -q

Os testes unitários executam sem rede, com o httpx interceptado por respx. O teste de smoke contra o sandbox executa somente quando a variável de ambiente FLUVPAY_TEST_KEY (prefixo fluv_test_) está presente; na ausência dela, o teste é pulado.

Licença

MIT.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

fluvpay-1.0.0.tar.gz (19.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

fluvpay-1.0.0-py3-none-any.whl (19.6 kB view details)

Uploaded Python 3

File details

Details for the file fluvpay-1.0.0.tar.gz.

File metadata

  • Download URL: fluvpay-1.0.0.tar.gz
  • Upload date:
  • Size: 19.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for fluvpay-1.0.0.tar.gz
Algorithm Hash digest
SHA256 de152a8555ff906c6e863e2975abdc41dec79715ab01fd15d0467819416b57ab
MD5 8c04600f3c3525a34d0b6648b9faf76b
BLAKE2b-256 f55c1901f29a0bef19bd683e665d42040a3bb51341eb485f556d2d2e2df639df

See more details on using hashes here.

File details

Details for the file fluvpay-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: fluvpay-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 19.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for fluvpay-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 b6ce8b092871509c41bfc1ab93a9344c572301c6bc693183d69c71b605fcfb1b
MD5 4b6d420625fa58c97db06497a6f5039c
BLAKE2b-256 308943921b1583247ac58466fc5584e995422b9048b587d206cbb7639bc3ec60

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page