Claude / Anthropic
Configure a BSPAY no Claude.ai, Claude Code e Anthropic API com Tool Use
Guia de integração via Claude.ai (web), Claude Code (CLI/IDE) e Anthropic API com Tool Use.
O catálogo completo de endpoints, HMAC, webhooks e erros vive em Integração com IA. Este guia é específico do Claude.
Claude.ai — Prompt direto
Cole no início da conversa:
Você é um especialista na BSPAY API v2.
Base: https://api.bspay.co · Auth: OAuth2 Client Credentials → Bearer JWT (1h)
Resposta: { success, data, request_id, timestamp } | erro: { success:false, error:{ code, message, group, retryable, details? } }
## HMAC obrigatório (rotas financeiras)
Cashout, internal_transfers/payment, conversions/new exigem:
X-Signature: hex(hmac_sha256(timestamp + "." + nonce + "." + body, signing_key))
X-Timestamp: <unix_seconds>
X-Nonce: <uuid_v4>
## Endpoints
- GET /v2/account/balance | /info/profile | /limits | /fees
- POST /v2/transactions/cashin { amount, currency, chain?, external_id, payer, postback_url }
- POST /v2/transactions/cashout { external_id, amount, currency, key, key_type?, network?, name?, bank_code? } [HMAC]
- POST /v2/transactions/wallet { currency, chain? } // wallet fixa permanente
- POST /v2/internal_transfers/payment { username, amount, currency, external_id? } [HMAC]
- POST /v2/conversions/rate | /simulate | /new { amount, base_currency, destination_currency, external_id? }
- POST /v2/account/transactions/list { page, page_size, status?, type?, source?, currency?, from_date?, to_date? }
- GET /v2/account/infractions { page?, page_size?, status?, type? } // PIX MED
- GET /v2/account/infractions/detail?id=<uuid>
- POST /v2/account/infractions/reply (multipart: id, message, files[])
## Webhooks (9 eventos)
cashin.{confirmed,refunded,expired} | cashout.{confirmed,failed,refunded}
wallet_deposit | transfer.confirmed | conversion.confirmed
chargeback.opened | chargeback.opened|chargeback.won|chargeback.lost|chargeback.canceled
Headers: X-BSPay-Event, X-BSPay-Signature (HMAC com callback_secret), X-BSPay-Timestamp.
Validar SEMPRE antes de processar (timing-safe compare).
## Status do ciclo
pending → confirmed | failed | cancelled | refunded
## chain vs network
- `chain` (cashin/wallet): blockchain de origem (livro-razão)
- `network` (cashout): rede de transmissão (pode ser L2: arbitrum/base/optimism)
Gere código limpo, com tratamento de erros e comentários em português.
Para operações que movem dinheiro, SEMPRE peça confirmação humana antes.
Claude Code — CLAUDE.md no projeto
Se você usa Claude Code, adicione um CLAUDE.md na raiz do seu projeto:
# BSPAY — Integração
- Base: https://api.bspay.co
- Docs completas: https://dev.bspay.co
- Auth: OAuth2 Client Credentials → Bearer JWT (1h)
## Quick reference
GET /v2/account/balance · /info/profile · /limits · /fees
POST /v2/transactions/cashin — { amount, currency, chain?, external_id, payer, postback_url }
POST /v2/transactions/cashout — HMAC obrigatório, response 202 async
POST /v2/transactions/wallet — wallet fixa BRL/MXN/cripto
POST /v2/internal_transfers/payment — HMAC
POST /v2/conversions/{rate|simulate|new} — campos: base_currency, destination_currency
POST /v2/account/transactions/list — extrato com filtros
GET /v2/account/infractions — PIX MED (disputas BACEN)
## HMAC (rotas financeiras)
X-Signature: hex(hmac_sha256(timestamp + "." + nonce + "." + body, SIGNING_KEY))
X-Timestamp: <unix_seconds>
X-Nonce: <uuid_v4>
Janela ±5min, nonce único 5min. Assinar BODY RAW (mesmos bytes enviados).
## Webhooks
Headers: X-BSPay-Event, X-BSPay-Signature, X-BSPay-Timestamp.
Validar HMAC com CALLBACK_SECRET antes de processar.
Eventos: cashin.confirmed, cashin.refunded, cashout.confirmed, cashout.failed,
wallet_deposit, transfer.confirmed, conversion.confirmed,
chargeback.opened, chargeback.opened|chargeback.won|chargeback.lost|chargeback.canceled.
## Convenções no projeto
- Auth: caching de token em Redis com TTL 50min (re-auth proativo)
- HMAC: helper em `lib/bspay/sign.ts` — nunca inlinar assinatura nas rotas
- Webhook: rota única `/api/webhook/bspay` valida HMAC + idempotência via tabela `webhook_events(transaction_id PRIMARY KEY)`
- Erros retryable: backoff exponencial 1s → 2s → 4s → 8s, máx 4 tentativas
Anthropic API — Tool Use
Implementação Python com auth, HMAC e tools mapeadas pra Claude.
import os, json, time, uuid, hmac, hashlib, base64
import requests
import anthropic
BASE = "https://api.bspay.co"
# ============================================================
# Cliente BSPAY com auth + HMAC
# ============================================================
class BSPay:
def __init__(self, client_id, client_secret, signing_key):
self.signing_key = signing_key
creds = base64.b64encode(f"{client_id}:{client_secret}".encode()).decode()
r = requests.post(
f"{BASE}/v2/oauth/token",
headers={"Authorization": f"Basic {creds}", "Content-Type": "application/json"},
json={"grant_type": "client_credentials"},
)
r.raise_for_status()
self.token = r.json()["access_token"]
def _h(self, extra=None):
h = {"Authorization": f"Bearer {self.token}", "Content-Type": "application/json"}
if extra: h.update(extra)
return h
def _signed_h(self, body: str):
ts = str(int(time.time()))
nonce = str(uuid.uuid4())
sig = hmac.new(self.signing_key.encode(), f"{ts}.{nonce}.{body}".encode(), hashlib.sha256).hexdigest()
return self._h({"X-Signature": sig, "X-Timestamp": ts, "X-Nonce": nonce})
# read
def balance(self):
return requests.get(f"{BASE}/v2/account/balance", headers=self._h()).json()
def list_transactions(self, **f):
return requests.post(f"{BASE}/v2/account/transactions/list", headers=self._h(), json=f).json()
def transaction(self, transaction_id):
return requests.post(
f"{BASE}/v2/account/transactions/list",
headers=self._h(), json={"transaction_id": transaction_id}
).json()
# cashin
def cashin_pix(self, amount, payer_name, payer_document, external_id):
body = {
"amount": amount, "currency": "BRL",
"external_id": external_id,
"payer": {"name": payer_name, "document": payer_document},
}
return requests.post(f"{BASE}/v2/transactions/cashin", headers=self._h(), json=body).json()
# cashout (HMAC)
def cashout_pix(self, amount, key, key_type, external_id, description=""):
body = json.dumps({
"external_id": external_id, "amount": amount, "currency": "BRL",
"key": key, "key_type": key_type, "description": description,
}, separators=(",", ":"))
return requests.post(f"{BASE}/v2/transactions/cashout", headers=self._signed_h(body), data=body).json()
# convert (HMAC)
def convert(self, amount, base_currency, destination_currency, external_id=None):
body = json.dumps({
"amount": amount,
"base_currency": base_currency,
"destination_currency": destination_currency,
"external_id": external_id or str(uuid.uuid4()),
}, separators=(",", ":"))
return requests.post(f"{BASE}/v2/conversions/new", headers=self._signed_h(body), data=body).json()
# ============================================================
# Tools no formato Anthropic
# ============================================================
TOOLS = [
{
"name": "balance",
"description": "Consulta o saldo da conta em todas as moedas (available/blocked/pending).",
"input_schema": {"type": "object", "properties": {}},
},
{
"name": "cashin_pix",
"description": "Gera QR Code PIX para receber pagamento em BRL. Retorna copy-paste e ID.",
"input_schema": {
"type": "object",
"required": ["amount", "payer_name", "payer_document", "external_id"],
"properties": {
"amount": {"type": "number"},
"payer_name": {"type": "string"},
"payer_document": {"type": "string", "description": "CPF/CNPJ"},
"external_id": {"type": "string"},
},
},
},
{
"name": "cashout_pix",
"description": "Envia PIX (saque). REQUER confirmação humana. Operação assíncrona — webhook chega depois.",
"input_schema": {
"type": "object",
"required": ["amount", "key", "key_type", "external_id"],
"properties": {
"amount": {"type": "number"},
"key": {"type": "string"},
"key_type": {"type": "string", "enum": ["cpf", "cnpj", "email", "phone", "random"]},
"external_id": {"type": "string"},
"description": {"type": "string"},
},
},
},
{
"name": "list_transactions",
"description": "Extrato paginado com filtros (status, type, currency, from_date, to_date).",
"input_schema": {
"type": "object",
"properties": {
"page": {"type": "integer"},
"page_size": {"type": "integer"},
"status": {"type": "string", "enum": ["pending", "confirmed", "cancelled", "failed"]},
"type": {"type": "string", "enum": ["cashin", "cashout"]},
"currency": {"type": "string"},
"from_date": {"type": "string"},
"to_date": {"type": "string"},
},
},
},
{
"name": "convert",
"description": "Converte uma moeda em outra (movimenta saldo)",
"input_schema": {
"type": "object",
"required": ["amount", "base_currency", "destination_currency"],
"properties": {
"amount": {"type": "number"},
"base_currency": {"type": "string"},
"destination_currency": {"type": "string"}, },
},
},
]
# ============================================================
# Loop de chat com Claude
# ============================================================
def run():
bspay = BSPay(
os.environ["BSPAY_CLIENT_ID"],
os.environ["BSPAY_CLIENT_SECRET"],
os.environ["BSPAY_SIGNING_KEY"],
)
client = anthropic.Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"])
messages = [{"role": "user", "content": "Gere um QR Code PIX de R$ 150 para Maria Silva, CPF 12345678901."}]
SYSTEM = (
"Você é um assistente financeiro com acesso à BSPAY. "
"SEMPRE confirme com o usuário antes de chamar tools que movem dinheiro (cashout/convert). "
"Para idempotência, gere external_id como UUID v4."
)
while True:
resp = client.messages.create(
model="claude-sonnet-4-5",
max_tokens=1024,
system=SYSTEM,
tools=TOOLS,
messages=messages,
)
if resp.stop_reason == "end_turn":
text = next((b.text for b in resp.content if b.type == "text"), "")
print(text)
return
# tool_use loop
messages.append({"role": "assistant", "content": resp.content})
tool_results = []
for block in resp.content:
if block.type == "tool_use":
result = getattr(bspay, block.name)(**block.input)
tool_results.append({
"type": "tool_result",
"tool_use_id": block.id,
"content": json.dumps(result),
})
messages.append({"role": "user", "content": tool_results})
run()
MCP Server (Model Context Protocol)
Para expor a BSPAY como MCP no Claude Desktop ou Claude Code:
{
"mcpServers": {
"bspay": {
"command": "node",
"args": ["bspay-mcp-server.js"],
"env": {
"BSPAY_CLIENT_ID": "seu_client_id",
"BSPAY_CLIENT_SECRET": "seu_client_secret",
"BSPAY_SIGNING_KEY": "sua_signing_key"
}
}
}
}
Construa o servidor com @modelcontextprotocol/sdk — exponha as mesmas operações do Tool Use acima como tools MCP.
Servidor MCP oficial da BSPAY está em roadmap. Enquanto isso, você pode escrever o seu — aproveitando que toda a auth + HMAC fica encapsulada num único módulo.
Boas práticas para Claude
Ative extended thinking em rotas críticas
Para cashout/convert use thinking parameter — Claude valida valor, destino e fee antes de executar.
tool_choice: "any" + system prompt forte
Force Claude a chamar tools (em vez de "responder com instruções") com tool_choice: {"type": "any"}. Combine com system prompt que define limites.
external_id consistente em retries
Em loops de tool_use, persista o external_id na primeira tentativa e reuse em retries. Isso garante idempotência mesmo se Claude re-chamar a tool.
Validate webhook antes de processar
No backend que recebe webhooks, valide HMAC X-BSPay-Signature com callback_secret. Não processe nada sem isso — ou um atacante pode forjar cashin.confirmed.
Nesta página
