qs.Cobranca.Pack
1.0.1
dotnet add package qs.Cobranca.Pack --version 1.0.1
NuGet\Install-Package qs.Cobranca.Pack -Version 1.0.1
<PackageReference Include="qs.Cobranca.Pack" Version="1.0.1" />
<PackageVersion Include="qs.Cobranca.Pack" Version="1.0.1" />
<PackageReference Include="qs.Cobranca.Pack" />
paket add qs.Cobranca.Pack --version 1.0.1
#r "nuget: qs.Cobranca.Pack, 1.0.1"
#:package qs.Cobranca.Pack@1.0.1
#addin nuget:?package=qs.Cobranca.Pack&version=1.0.1
#tool nuget:?package=qs.Cobranca.Pack&version=1.0.1
qs.Cobranca.Pack
Cliente .NET da API qsse.Cobranca (SaaS multitenant/multibanco de boletos da suíte QSSE). Abstrai emissão, consulta, PDF, baixa, alteração, linha do tempo, totalizadores, emissão em lote e resolução da conta emissora por CNPJ, resolvendo autenticação, idempotência, paginação, retry de transientes e tradução de erros.
- Targets:
net8.0enet10.0 - Dependências:
Microsoft.Extensions.Http,Microsoft.Extensions.Options - Guia completo de integração:
QSSE-DOCS/qsse.cobranca/integracao/
Instalação
dotnet add package qs.Cobranca.Pack
Registro (DI)
builder.Services.AddQsCobranca(o =>
{
o.BaseAddress = new Uri("https://cobranca.qsse.com.br");
o.ApiKey = builder.Configuration["Cobranca:ApiKey"]; // header X-Api-Key
});
Com JWT do qsAccount em vez de API key:
builder.Services.AddQsCobranca(o =>
{
o.BaseAddress = new Uri("https://cobranca.qsse.com.br");
o.TokenProvider = async ct => await tokenCache.GetAccessTokenAsync(ct);
});
AddQsCobranca devolve o IHttpClientBuilder do client nomeado — encadeie políticas próprias
(AddStandardResilienceHandler, logging, proxy) se precisar.
Sem container de DI (console, Windows Service legado):
ICobrancaClient cobranca = CobrancaClient.Create(o =>
{
o.BaseAddress = new Uri("https://cobranca.qsse.com.br");
o.ApiKey = "...";
});
Guarde a instância como singleton: ela é dona do
HttpClient.
Multiempresa: achar a conta emissora pelo CNPJ
Um cliente pode ter várias contas bancárias, cada uma de uma empresa beneficiária (CNPJ) diferente. O ERP conhece o CNPJ que está faturando, não o GUID da conta:
var conta = await cobranca.Contas.ObterPorCnpjAsync(empresa.Cnpj)
?? throw new InvalidOperationException($"Sem conta ativa para o CNPJ {empresa.Cnpj}.");
// ... e vai em BankConfigId na emissão
ObterPorCnpjAsync compara só dígitos e considera apenas conta ativa; havendo mais de uma para o
mesmo CNPJ, a padrão do cliente desempata. ListarAsync() devolve todas as contas com banco,
agência/conta/carteira, status, validade do certificado e beneficiário.
Omitir BankConfigId na emissão usa a conta padrão do cliente — em cenário multiempresa isso
emite no CNPJ errado sem avisar. .Contas é somente leitura: cadastrar conta e enviar
credenciais/certificado é ato de usuário no Portal.
Emitir
var boleto = await cobranca.Boletos.EmitirAsync(
new EmitirBoletoRequest(
Valor: 1500.00m,
Vencimento: DateOnly.FromDateTime(DateTime.Today.AddDays(10)),
Pagador: new PagadorInput("ACME LTDA", "12345678000199", "87300-000", Numero: 100),
Encargos: new EncargosInput(MultaPercentual: 2, JurosMesPercentual: 1),
SeuNumero: "FAT-2026-000123"),
idempotencyKey: "FAT-2026-000123"); // estável: reexecutar a rotina não emite duas vezes
Console.WriteLine(boleto.LinhaDigitavel);
A chave de idempotência é o ponto de atenção da integração: passe um valor derivado do documento
de origem. Sem ela o pacote gera uma chave nova a cada chamada (AutoIdempotencyKey), o que
protege apenas contra o retry interno desta chamada — não contra o ERP rodando a rotina de novo.
Consultar, listar e conciliar
var atual = await cobranca.Boletos.ObterAsync(boleto.Id);
var pagina = await cobranca.Boletos.ListarAsync(
new BoletoFiltro(Status: BoletoStatus.Vencido, VencimentoAte: DateOnly.FromDateTime(DateTime.Today)),
page: 1, pageSize: 100);
// Percorre todas as páginas
await foreach (var b in cobranca.Boletos.ListarTodosAsync(new BoletoFiltro(SeuNumero: "FAT-2026-000123")))
Conciliar(b);
byte[] pdf = await cobranca.Boletos.ObterPdfAsync(boleto.Id);
var eventos = await cobranca.Boletos.ListarEventosAsync(boleto.Id);
var resumo = await cobranca.Boletos.ObterResumoAsync();
Baixar e alterar
await cobranca.Boletos.BaixarAsync(boleto.Id, "Pago em espécie no caixa");
await cobranca.Boletos.AlterarAsync(boleto.Id, new AlterarBoletoRequest(
NovoVencimento: DateOnly.FromDateTime(DateTime.Today.AddDays(30))));
Lote
var itens = faturas.Select(f => new LoteItemInput(
f.Valor, f.Vencimento, new PagadorInput(f.Nome, f.Documento, f.Cep), SeuNumero: f.Numero)).ToList();
// Fatia em lotes de 50 (teto da API) e envia todos
var aceites = await cobranca.Lotes.EmitirFatiadoAsync(itens);
// Em rotina batch, dá para esperar o processamento terminar
var lote = await cobranca.Lotes.AguardarConclusaoAsync(aceites[0].LoteId);
foreach (var item in lote.Itens.Where(i => i.ErrorCode is not null))
Log(item.SeuNumero, item.ErrorCode, item.ErrorMessage);
Quando IdempotencyKey do item não é informada, o pacote usa o SeuNumero — reprocessar o mesmo
lote não reemite os títulos.
Em serviços que já recebem webhook, prefira reagir ao evento lote.concluido em vez de manter uma
thread em AguardarConclusaoAsync.
Erros
Falha de negócio vira exceção tipada, com o slug da API preservado em Code:
| Exceção | HTTP | Situação |
|---|---|---|
CobrancaValidationException |
400/422 | dados rejeitados (invalid_cep, invalid_valor, …) |
CobrancaNotFoundException |
404 | boleto/lote inexistente ou de outro cliente |
CobrancaConflictException |
409 | estado incompatível (bank_config_missing, invalid_state) |
CobrancaAuthException |
401/403 | credencial inválida, sem escopo ou cliente suspenso |
CobrancaRateLimitException |
429 | limite de requisições do cliente |
CobrancaBankUnavailableException |
503 | banco emissor fora do ar — transitório, o título não foi registrado |
CobrancaApiException |
demais | erro genérico, com RawBody para diagnóstico |
try
{
await cobranca.Boletos.EmitirAsync(request, idempotencyKey: fatura.Numero);
}
catch (CobrancaBankUnavailableException ex)
{
agendador.Reagendar(fatura, ex.RetryAfter ?? TimeSpan.FromMinutes(1));
}
catch (CobrancaValidationException ex)
{
foreach (var e in ex.Errors)
Log(e.Code, e.Description);
}
Retry
408/429/5xx e falhas de conexão são repetidos com backoff exponencial + jitter, respeitando
Retry-After (MaxAttempts, padrão 3). POST só é repetido quando carrega Idempotency-Key —
sem a chave, repetir um timeout que na verdade chegou ao banco cobraria o pagador duas vezes.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Microsoft.Extensions.Http (>= 8.0.1)
- Microsoft.Extensions.Options (>= 8.0.2)
-
net8.0
- Microsoft.Extensions.Http (>= 8.0.1)
- Microsoft.Extensions.Options (>= 8.0.2)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.