Skip to content

Repository files navigation

Asaas

Asaas SDK for .NET

Cliente .NET tipado, sem dependências externas, para a API v3 do Asaas.

NuGet VersionNuGet DownloadsCIIntegration (sandbox)License: MIT.NET 10Schema-first

Instalação · Quick Start · Managers · Conformidade · Changelog · Contribuir


Sumário


Visão Geral

Asaas.Api é um SDK .NET não-oficial que cobre 100% da API v3 documentada do Asaas — mais de 150 endpoints distribuídos em 27 domain managers. Foi projetado para ser:

  • Type-safe: enums tipados para todos os status, billing types, frequências e códigos. Sem strings mágicas.
  • Schema-first: cada modelo é verificado endpoint-a-endpoint contra a especificação OpenAPI oficial via MCP. Contract tests congelam o shape JSON.
  • Sem dependências externas: usa apenas System.Text.Json (built-in do .NET 10).
  • Production-ready: 664 testes unit/contract + 15 integration tests reais contra api-sandbox.asaas.com rodando em CI nightly.

Veja CONFORMANCE.md para o relatório de auditoria endpoint-a-endpoint.

Destaques

  • 27 managers prontos para usar — Customer, Payment, Subscription, Installment, Pix (estático, automático, recorrente), Webhook, Invoice, Anticipation, Transfer, PaymentLink, CreditCard, PaymentDunning, BillPayment, MobilePhoneRecharge, Notification, FiscalInfo, Finance, MyAccount, AsaasAccount, Wallet, CreditBureauReport, Chargeback, Escrow, Checkout, Sandbox.
  • Modelos auditados contra o schema oficial — 42 famílias de bugs corrigidos na auditoria v3.2.0 (campos inventados removidos, enums incompletos completados, nullables corrigidos, casing de filtros padronizado).
  • Cobertura de testes em três camadas:
    • Unit tests para cada manager (chamada HTTP correta, route, método)
    • Contract tests com fixtures dos exemplos oficiais MCP (shape JSON congelado)
    • Integration tests opcionais contra sandbox real (skip automático sem token)
  • Robustez de runtime:bool? em filtros serializa lowercase (true/false, não True/False), decimal? usa InvariantCulture (12.5, não 12,5 em pt-BR), DateTime? usa formato ISO em qualquer cultura.
  • Sem mocks frágeis: o test runner real (Moq + MockHttpMessageHandler) injeta resposta HTTP no BaseManager, validando o JSON exato que sairia na rede.
  • CI pronto: workflows GitHub Actions para build/test em todo PR e workflow separado de integration tests com secret ASAAS_SANDBOX_TOKEN.

Requisitos

  • .NET 10 SDK ou superior
  • Conta Asaas com access_token (sandbox ou produção)

Instalação

dotnet add package Asaas.Api
Install-Package Asaas.Api
<PackageReferenceInclude="Asaas.Api"Version="3.2.0" />

Quick Start

usingCodout.Apis.Asaas;usingCodout.Apis.Asaas.Core;usingCodout.Apis.Asaas.Models.Common.Enums;usingCodout.Apis.Asaas.Models.Customer;usingCodout.Apis.Asaas.Models.Payment;// 1. Configurevarsettings=newApiSettings(accessToken:Environment.GetEnvironmentVariable("ASAAS_TOKEN")!,applicationName:"MeuApp/1.0",asaasEnvironment:AsaasEnvironment.SANDBOX);varasaas=newAsaasApi(settings);// 2. Crie um clientevarcustomer=awaitasaas.Customer.Create(newCreateCustomerRequest{Name="Maria da Silva",CpfCnpj="01020558075",Email="maria@example.com"});if(!customer.WasSuccessful()){foreach(varerrorincustomer.Errors)Console.WriteLine($"[{error.Code}] {error.Description}");return;}// 3. Crie uma cobrança Pixvarpayment=awaitasaas.Payment.Create(newCreatePaymentRequest{CustomerId=customer.Data.Id,BillingType=BillingType.PIX,Value=150.00m,DueDate=DateTime.UtcNow.Date.AddDays(7),Description="Pedido #1234"});// 4. Obtenha o QR Code Pixvarqr=awaitasaas.Payment.GetPixQrCode(payment.Data.Id);Console.WriteLine(qr.Data.Payload);// copia-e-colaConsole.WriteLine(qr.Data.EncodedImage);// base64 PNG

Conceitos Centrais

Ambientes

AmbienteEnumBase URL
SandboxAsaasEnvironment.SANDBOXhttps://api-sandbox.asaas.com/v3
ProduçãoAsaasEnvironment.PRODUCTIONhttps://api.asaas.com/v3

Use sempre Sandbox durante desenvolvimento. O manager asaas.Sandbox lança InvalidOperationException se for chamado em ambiente de produção.

Responses tipadas

Toda chamada retorna ResponseObject<T> (item único) ou ResponseList<T> (paginada). Ambos expõem WasSuccessful(), StatusCode e Errors:

ResponseObject<Customer>response=awaitasaas.Customer.Find("cus_123");if(response.WasSuccessful()){Customercustomer=response.Data;Console.WriteLine(customer.Name);}else{Console.WriteLine($"Status: {response.StatusCode}");foreach(varerrorinresponse.Errors)Console.WriteLine($"[{error.Code}] {error.Description}");}
ResponseList<Payment>list=awaitasaas.Payment.List(offset:0,limit:10);Console.WriteLine($"Total: {list.TotalCount} — HasMore: {list.HasMore}");foreach(varpaymentinlist.Data)Console.WriteLine($"{payment.Id} — R$ {payment.Value}{payment.Status}");

Filtros e paginação

A maioria dos List aceita um filtro opcional. Todos os filtros são objetos tipados que herdam de RequestParameters:

varpayments=awaitasaas.Payment.List(0,20,newPaymentListFilter{CustomerId="cus_123",BillingType=BillingType.PIX,Status=PaymentStatus.PENDING,DueDateGE=DateTime.UtcNow.Date,DueDateLE=DateTime.UtcNow.Date.AddMonths(1),Anticipated=false});

bool?, DateTime?, decimal? e enums são serializados no formato exato que a API exige, com fallback para InvariantCulture (resolve o bug clássico de 12,5 em vez de 12.5 em pt-BR).

Tratamento de erros

varresult=awaitasaas.Payment.Create(request);if(result.StatusCode==HttpStatusCode.BadRequest){// Validação de regras de negócio do AsaasvarinvalidCustomer=result.Errors.FirstOrDefault(e =>e.Code=="invalid_customer");if(invalidCustomeris not null)// cliente não existe ou não tem cobrança permitida
...}if(result.StatusCode==HttpStatusCode.Unauthorized)// access_token inválido ou expirado
...if(result.StatusCode==HttpStatusCode.TooManyRequests)// backoff exponencial recomendado
...

Cultura e serialização

A serialização JSON usa configuração centralizada em Core/JsonSerializerConfiguration.cs:

  • camelCase automático (CustomerIdcustomerId)
  • null-ignoring (campos não setados não vão na requisição)
  • enums como string (com SafeEnumConverterFactory que aceita valores novos sem quebrar)
  • datas flexíveis (aceita 2025-01-01, 2025-01-01T10:00:00, 2025-01-01 10:00:00, etc.)

Query strings (filtros) usam RequestParameters que sempre serializa em InvariantCulture, independente da cultura do thread.

Managers Disponíveis

ManagerPropriedadeEndpointsDescrição
Clientesasaas.Customer7CRUD + notificações
Cobrançasasaas.Payment28+Boleto/Pix/Cartão + splits + refunds + documents + billing/viewing info + simulate + limits
Parcelamentosasaas.Installment10CRUD + refund + splits + paymentBook
Assinaturasasaas.Subscription12CRUD + creditCard + invoiceSettings + payments
Links de pagamentoasaas.PaymentLink11CRUD + imagens
Pixasaas.Pix13AddressKeys, QrCodes, Transactions (com filter), tokenBucket, decode, pay
Pix Automáticoasaas.PixAutomatic6Autorizações recorrentes Bacen + payment instructions
Pix Recorrenteasaas.PixRecurring5Recorrências parceladas + itens
Webhooksasaas.Webhook6CRUD + removeBackoff (~100 eventos disponíveis)
Notas Fiscaisasaas.Invoice7Schedule, Find, List (com 7 filtros), Update, Authorize, Cancel
Informações Fiscaisasaas.FiscalInfo4CreateOrUpdate + Find + lookups municipais
Financeiroasaas.Finance4Balance + Statistics (com filter) + Split
Transferênciasasaas.Transfer5Para Asaas/banco/Pix + Find + List + Cancel
Antecipaçõesasaas.Anticipation8CRUD + Simulate + Limits + Automatic configuration
Negativaçõesasaas.PaymentDunning9CRUD + Simulate + History + PartialPayments + ResendDocument
Pagamento de contasasaas.BillPayment5CRUD + Simulate + Cancel
Recarga celularasaas.MobilePhoneRecharge5CRUD + GetProvider
Notificaçõesasaas.Notification2Update + BatchUpdate
Cartão de créditoasaas.CreditCard3TokenizeCreditCard + PreAuthorization config
Contas Asaas (subaccounts)asaas.AsaasAccount6CRUD + ResendActivationLink + AccessTokens
Minha contaasaas.MyAccount10CommercialInfo + Status + Fees + AccountNumber + PaymentCheckoutConfig + Documents
Carteirasasaas.Wallet1List
Consulta SERASAasaas.CreditBureauReport3Create + Find + List (com filter)
Chargebacksasaas.Chargeback3List + FindByPayment + CreateDispute
Escrowasaas.Escrow6Configuração subconta/padrão + payment escrow
Checkoutasaas.Checkout2Create + Cancel
Sandboxasaas.Sandbox3ApproveAccount + ConfirmPayment + ForceOverdue (bloqueado em PRODUCTION)

Lista completa de endpoints por manager: CONFORMANCE.md §1–§29.

Exemplos por Domínio

Cobranças (Pix / Boleto / Cartão)

usingCodout.Apis.Asaas.Models.Common;usingCodout.Apis.Asaas.Models.Common.Enums;usingCodout.Apis.Asaas.Models.Payment;// Pixvarpix=awaitasaas.Payment.Create(newCreatePaymentRequest{CustomerId="cus_123",BillingType=BillingType.PIX,Value=150m,DueDate=DateTime.UtcNow.Date.AddDays(7),Description="Pedido #1234"});// Boleto com multa e jurosvarboleto=awaitasaas.Payment.Create(newCreatePaymentRequest{CustomerId="cus_123",BillingType=BillingType.BOLETO,Value=1000m,DueDate=DateTime.UtcNow.Date.AddDays(7),Discount=newDiscount{Value=50m,DueDateLimitDays=3,Type=DiscountType.FIXED},Interest=newInterest{Value=2m},// % ao mêsFine=newFine{Value=1m,Type=FineType.PERCENTAGE}});// Cartão tokenizado (em endpoint dedicado)varwithCard=awaitasaas.Payment.CreateWithCreditCard(newCreatePaymentRequest{CustomerId="cus_123",BillingType=BillingType.CREDIT_CARD,Value=299.90m,DueDate=DateTime.UtcNow.Date,CreditCardToken="tok_a75a1d98-c52d-4a6b",// tokenizado previamenteRemoteIp="200.123.45.67"});

Assinaturas

usingCodout.Apis.Asaas.Models.Subscription;usingCodout.Apis.Asaas.Models.Subscription.Enums;varsub=awaitasaas.Subscription.Create(newCreateSubscriptionRequest{CustomerId="cus_123",BillingType=BillingType.CREDIT_CARD,Value=99.90m,NextDueDate=DateTime.UtcNow.Date.AddDays(30),Cycle=Cycle.MONTHLY,Description="Plano Premium",CreditCard=newCreditCardRequest{/* ... */},CreditCardHolderInfo=newCreditCardHolderInfoRequest{/* ... */}});// Listar cobranças geradas pela assinaturavarpayments=awaitasaas.Subscription.ListPayments("sub_123",0,20);// Filtros novos (v3.2.0 — B-27e)varfiltered=awaitasaas.Subscription.List(0,50,newSubscriptionListFilter{Status=SubscriptionStatus.INACTIVE,DeletedOnly=false,Sort="dateCreated",Order="desc"});

Links de pagamento

usingCodout.Apis.Asaas.Models.PaymentLink;usingCodout.Apis.Asaas.Models.PaymentLink.Enums;varlink=awaitasaas.PaymentLink.Create(newCreatePaymentLinkRequest{Name="Produto XYZ",Value=199.90m,BillingType=BillingType.UNDEFINED,ChargeType=ChargeType.DETACHED,DueDateLimitDays=10});Console.WriteLine($"Compartilhe: {link.Data.Url}");

Pix

usingCodout.Apis.Asaas.Models.Pix;usingCodout.Apis.Asaas.Models.Pix.Enums;// Criar QR Code estáticovarqr=awaitasaas.Pix.CreateStaticQrCode(newCreatePixStaticQrCodeRequest{AddressKey="minha-chave-pix",Description="Doação",Value=50m});// Criar chave EVP (aleatória)varkey=awaitasaas.Pix.CreateAddressKey(newCreatePixAddressKeyRequest{Type=PixAddressKeyType.EVP});// Listar transações com filtro de status (v3.2.0 — novo)vartxs=awaitasaas.Pix.ListTransactions(0,20,newPixTransactionListFilter{Status=PixTransactionStatus.AWAITING_REQUEST});

Webhooks

usingCodout.Apis.Asaas.Models.Webhook;usingCodout.Apis.Asaas.Models.Webhook.Enums;varwebhook=awaitasaas.Webhook.Create(newCreateWebhookRequest{Name="Notificações de pagamento",Url="https://meusite.com/webhook/asaas",Email="ops@meusite.com",Enabled=true,Interrupted=false,ApiVersion=3,AuthToken="whsec_min_32_caracteres_para_assinar_callbacks",SendType=WebhookSendType.SEQUENTIALLY,Events=[WebhookEvent.PAYMENT_CONFIRMED,WebhookEvent.PAYMENT_RECEIVED,WebhookEvent.PAYMENT_OVERDUE,WebhookEvent.PAYMENT_REFUNDED]});

Nota: Este SDK expõe WebhookManager para configurar endpoints, mas não fornece decoders tipados para os payloads que o Asaas envia para a sua URL. A deserialização do payload recebido fica a cargo do consumidor.

Transferências

usingCodout.Apis.Asaas.Models.Transfer;usingCodout.Apis.Asaas.Models.Transfer.Enums;// Para outra conta Asaas (POST /v3/transfers/)awaitasaas.Transfer.TransferToAsaasAccount(newAsaasAccountTransferRequest{WalletId="wallet_destino",Value=500m});// Para banco externo (TED ou Pix — POST /v3/transfers)awaitasaas.Transfer.TransferToBankAccount(newBankAccountTransferRequest{Value=1000m,BankAccount=newBankAccount{Bank=newBank{Code="341"},OwnerName="Empresa LTDA",CpfCnpj="12345678000100",Agency="1234",Account="56789",AccountDigit="0",BankAccountType=BankAccountType.CONTA_CORRENTE}});// Listar com filtros de data (v3.2.0 — B-29h)varlist=awaitasaas.Transfer.List(0,50,newTransferListFilter{DateCreatedGE=DateTime.UtcNow.Date.AddDays(-30),DateCreatedLE=DateTime.UtcNow.Date});

Notas fiscais (NFS-e)

usingCodout.Apis.Asaas.Models.Invoice;usingCodout.Apis.Asaas.Models.Common;varinvoice=awaitasaas.Invoice.Schedule(newCreateInvoiceRequest{PaymentId="pay_123",ServiceDescription="Serviço de consultoria",Observations="Referente ao mês de janeiro",Value=1500m,Deductions=0m,EffectiveDate=DateTime.UtcNow.Date,MunicipalServiceName="Consultoria em TI",Taxes=newTaxes{RetainIss=false,Iss=2m,Pis=0.65m,Cofins=3m,Csll=1m,Inss=0m,Ir=1.5m}});awaitasaas.Invoice.Authorize(invoice.Data.Id);// Lookup de códigos municipaisvarservices=awaitasaas.FiscalInfo.ListServices(description:"consultoria");

Saldo e estatísticas

varbalance=awaitasaas.Finance.GetBalance();Console.WriteLine($"Saldo: R$ {balance.Data.Value}");// Estatísticas com filtros (v3.2.0 — B-37b)varstats=awaitasaas.Finance.GetPaymentStatistics(newPaymentStatisticsFilter{BillingType=BillingType.PIX,Status=PaymentStatus.RECEIVED,DateCreatedGE=DateTime.UtcNow.Date.AddDays(-30),DateCreatedLE=DateTime.UtcNow.Date});Console.WriteLine($"Quantidade: {stats.Data.Quantity} — Total: R$ {stats.Data.Value}");// Split a receber/enviar (v3.2.0 — schema corrigido B-37a)varsplit=awaitasaas.Finance.GetSplitStatistics();Console.WriteLine($"A receber: R$ {split.Data.Income} — A enviar: R$ {split.Data.Value}");

Sandbox (apenas testes)

// Em AsaasEnvironment.SANDBOX você pode acelerar fluxos de teste:awaitasaas.Sandbox.ApproveAccount();// aprova conta sandboxawaitasaas.Sandbox.ConfirmPayment("pay_123");// confirma pagamento sem boleto/pixawaitasaas.Sandbox.ForceOverdue("pay_123");// força vencimento imediato// Em PRODUCTION todos lançam InvalidOperationException antes de fazer HTTP.

Configuração Avançada

Timeout customizado

varsettings=newApiSettings("TOKEN","MeuApp/1.0",AsaasEnvironment.PRODUCTION){TimeOut=TimeSpan.FromSeconds(60)};

User-Agent

O parâmetro applicationName em ApiSettings se torna parte do User-Agent da requisição, ajudando o suporte Asaas a identificar a integração em caso de troubleshooting:

newApiSettings("TOKEN","ECommerceXYZ/2.5.0",AsaasEnvironment.PRODUCTION);// User-Agent enviado: ECommerceXYZ/2.5.0

Reaproveitamento de conexões

BaseManager usa um SocketsHttpHandler estático e compartilhado por toda a instância de AsaasApi. Recomenda-se manter um único AsaasApi como singleton ao longo do ciclo de vida da aplicação (registrar no DI com AddSingleton).

// ASP.NET Corebuilder.Services.AddSingleton(_ =>newAsaasApi(newApiSettings(accessToken:builder.Configuration["Asaas:Token"]!,applicationName:"MeuApp/1.0",asaasEnvironment:AsaasEnvironment.PRODUCTION)));

Qualidade e Conformidade

Esta biblioteca passa por auditoria schema-first contínua contra o MCP oficial do Asaas, garantindo que cada modelo, enum, filtro e nome de campo bate exatamente com a especificação OpenAPI publicada.

MétricaValor
Managers auditados27 / 27 (100%)
Endpoints cobertos~150
Famílias de bugs corrigidos42 (B-19 a B-42)
Testes unit + contract664 passando
Integration tests sandbox15 / 15 passando
Warnings de build0

Relatório completo: CONFORMANCE.md — inclui tabela endpoint-a-endpoint por manager, lista de bugs por padrão (envelope, casing, nullable, enums inventados, etc.) e riscos remanescentes classificados.

Testes

Pré-requisitos

Build

dotnet build Codout.Apis.Asaas/

Suite local (unit + contract)

# Roda todos os testes que não dependem do sandbox
dotnet test Codout.Apis.Asaas.Tests/ --filter "Category!=Integration"
# Tests de um manager específico
dotnet test Codout.Apis.Asaas.Tests/ --filter "FullyQualifiedName~CustomerManagerTests"

Integration tests (sandbox real)

Integration tests fazem chamadas reais contra api-sandbox.asaas.com. São puladas automaticamente quando a variável de ambiente ASAAS_SANDBOX_TOKEN está vazia — o CI local não quebra:

$env:ASAAS_SANDBOX_TOKEN="aact_YTU0..."
dotnet test Codout.Apis.Asaas.Tests/--filter "Category=Integration"

CI

O repositório expõe dois workflows GitHub Actions:

  • ci.yml — roda em todo push/PR. Build + testes unit/contract (integration filtrados fora).
  • integration-sandbox.yml — dispatch manual + nightly às 04:00 UTC. Usa o secret ASAAS_SANDBOX_TOKEN configurado no repositório.

Empacotar localmente

dotnet pack Codout.Apis.Asaas/ -c Release

Arquitetura

Codout.Apis.Asaas/
├── AsaasApi.cs # Facade — entry point com 27 managers via Lazy<T>
├── Core/
│ ├── ApiSettings.cs # Configuração (token, ambiente, timeout, app name)
│ ├── BaseManager.cs # Base HTTP (GET/POST/PUT/DELETE), SocketsHttpHandler estático
│ ├── JsonSerializerConfiguration.cs # camelCase + SafeEnumConverterFactory + FlexibleDateTimeConverter
│ ├── RequestParameters.cs # Query string builder (InvariantCulture, bool lowercase)
│ ├── Response/
│ │ ├── Base/BaseResponse.cs # StatusCode + Errors + WasSuccessful()
│ │ ├── ResponseObject<T>.cs
│ │ └── ResponseList<T>.cs # envelope padrão {object, hasMore, totalCount, limit, offset, data}
│ └── Extension/ # DateTime, StatusCode, String helpers
├── Managers/ # 27 domain managers
└── Models/ # Request/Response por domínio (1 classe por arquivo)
├── Customer/
├── Payment/
├── Pix/
├── ...
└── Common/ # Discount, Interest, Fine, CreditCard, Split, etc.

Versionamento

Este projeto segue Versionamento Semântico:

  • MAJOR (x.0.0): mudanças incompatíveis — campos removidos, tipos alterados, métodos renomeados.
  • MINOR (3.x.0): novos endpoints, novos campos opcionais, novos filtros, bug fixes que mudem tipo de campo opcional (e.g. stringenum?).
  • PATCH (3.2.x): bug fixes não-comportamentais, melhorias de doc, cleanup.

Cada release tem uma entrada detalhada no CHANGELOG.md com:

  • Lista de breaking changes por modelo
  • Bugs corrigidos com referência ao código B-XX rastreável
  • Métricas de testes

Roadmap

Itens não-bloqueantes que podem entrar em releases futuras:

  • Decoders tipados para os payloads de webhook recebidos do Asaas (atualmente, consumidores deserializam manualmente).
  • Lookups adicionais do FiscalInfo (federalServiceCodes, nbsCodes, operationIndicatorCodes, taxClassificationCodes, taxSituationCodes, nationalPortal).
  • Auditoria contínua quando a spec da Reforma Tributária estabilizar.

Contribuindo

Contribuições são bem-vindas! Para mudanças significativas, abra uma issue primeiro para discutir o que você gostaria de mudar.

  1. Faça fork do repositório.
  2. Crie uma branch para sua feature ou fix (git checkout -b feature/minha-feature).
  3. Audite o(s) endpoint(s) afetado(s) contra o MCP oficial. Adicione/atualize o fixture em Codout.Apis.Asaas.Tests/Fixtures/ e o contract test correspondente.
  4. Garanta que dotnet test --filter "Category!=Integration" passa.
  5. Atualize CONFORMANCE.md com o(s) bug(s) corrigido(s) seguindo a numeração B-XX.
  6. Atualize CHANGELOG.md com a entrada.
  7. Abra um Pull Request descrevendo a mudança e referenciando o(s) endpoint(s) MCP consultado(s).

Segurança

Se você descobrir uma vulnerabilidade de segurança, não abra uma issue pública. Em vez disso, envie um email para o autor (veja LICENSE para contato) ou abra um security advisory privado.

Por convenção:

  • Tokens da Asaas (access_token, ASAAS_SANDBOX_TOKEN) nunca devem ser commitados.
  • O User-Agent enviado pela biblioteca não inclui PII.
  • Logs gerados pelo SDK não incluem o access_token.

Licença

MIT © Clovis Coli Jr / Codout

Aviso

Esta é uma biblioteca não-oficial. Não possui vínculo, endosso ou suporte oficial da Asaas. Para suporte oficial da API, consulte a documentação do Asaas ou o Help Center.

Para questões específicas deste SDK, use as issues do GitHub.

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages