Status: ✅ AUDITORIA COMPLETA — 27/27 MANAGERS SCHEMA-FIRST Metodologia: cada endpoint listado abaixo foi consultado via MCP
asaas(mcp__asaas__get-endpoint). Models foram verificados campo-a-campo contra o schema OpenAPI. Fixtures criadas a partir dos exemplos oficiais. Contract tests congelam o shape JSON.Resultado: 664 testes unit/contract passando + 15 integration tests passando contra sandbox real (run #26378491985, 2026-05-25, 6.7s). 27/27 managers auditados, 42 famílias de bugs (B-19 a B-42) corrigidas no total, 0 warnings de build.
CI:
.github/workflows/ci.yml— unit/contract em todo push/PR.github/workflows/integration-sandbox.yml— integration tests com secretASAAS_SANDBOX_TOKEN(manual + nightly)
| Status | Significado |
|---|---|
| ✅ | Schema verificado via MCP, model alinhado, fixture criada, contract test passando |
| Verificado mas com divergência conhecida; documentada | |
| 🔴 | Divergência sem correção (não deveria existir até fim da auditoria) |
| ⏳ | Pendente nesta auditoria |
| Nível | O que valida | Por endpoint |
|---|---|---|
| Contract test | Shape JSON (chaves exatas, casing, enums, envelope) | ✅ se marcado abaixo |
| Unit test | Manager chama URL/método corretos, deserialização básica | ✅ pré-existente |
| Integration test | Chamada real contra api-sandbox.asaas.com | Apenas endpoints listados em §99 |
| Endpoint | MCP consultado | Model | Fixture | Contract test | Status |
|---|---|---|---|---|---|
GET /v3/payments/limits |
✅ | PaymentLimits (Creation.Daily.{Limit,Used,WasReached}) |
Payment/limits-response.json |
PaymentLimits_DeserializesFromOfficialFixture |
✅ |
POST /v3/payments/simulate (request) |
✅ | SimulatePaymentRequest (value, billingTypes[], installmentCount?) |
Payment/simulate-request-minimal.json, Payment/simulate-request-with-installments.json |
SimulatePaymentRequest_* (3 tests) |
✅ |
POST /v3/payments/simulate (response) |
✅ | SimulatedPayment (value, creditCard?, bankSlip?, pix?) |
Payment/simulate-response.json |
SimulatedPaymentResponse_DeserializesFromOfficialFixture |
✅ |
Erros oficiais ({errors:[{code,description}]}) também validados via fixture compartilhada (error-response.json).
| Endpoint | MCP | Model | Fixture | Contract test | Status |
|---|---|---|---|---|---|
POST /v3/checkouts (request) |
✅ | CreateCheckoutRequest (billingTypes, chargeTypes, callback, items required) |
Checkout/create-request-minimal.json, create-request-recurrent.json |
CreateCheckoutRequest_* (3 tests) |
✅ |
POST /v3/checkouts (response) |
✅ | Checkout (id, link, status enum, subscriptions, customerData com city/addressNumber int) |
Checkout/response.json |
CheckoutResponse_DeserializesFromOfficialFixture_FullShape, _UsesSplitSingular_OnResponse |
✅ |
POST /v3/checkouts/{id}/cancel |
✅ | mesmo response Checkout, body vazio |
reusa response.json |
(idem) | ✅ |
Enum CheckoutStatus ACTIVE/CANCELED/EXPIRED/PAID |
✅ | enum tipado | inline | CheckoutStatus_AllValuesDeserialize |
✅ |
Quirk documentado: request usa splits (plural), response usa split (singular). Comentário no CreateCheckoutRequest.cs evita "correções" futuras erradas.
Bug pré-existente corrigido em paralelo: Subscription.Enums.Cycle estava faltando o valor BIMONTHLY (presente no schema oficial de SubscriptionSaveRequestCycle e CheckoutSessionSubscriptionCycle).
| Endpoint | MCP | Model | Fixture | Contract test | Status |
|---|---|---|---|---|---|
POST /v3/accounts/{id}/escrow |
✅ | SaveEscrowConfigRequest / response EscrowConfig (daysToExpire required, enabled/isFeePayer optional) |
Escrow/config-request.json, config-response.json |
SaveEscrowConfigRequest_HasCorrectFieldNames, _NoFakeFields |
✅ |
GET /v3/accounts/{id}/escrow |
✅ | EscrowConfig (mesmo schema) |
Escrow/config-response.json |
EscrowConfig_DeserializesFromOfficialFixture, _OptionalBoolsAreNullableInResponse |
✅ |
POST /v3/accounts/escrow |
✅ | mesmo AccountPaymentEscrowConfigDTO |
reusa | (idem) | ✅ |
GET /v3/accounts/escrow |
✅ | mesmo AccountPaymentEscrowConfigDTO |
reusa | (idem) | ✅ |
POST /v3/escrow/{id}/finish |
✅ | body {} vazio → retorna Payment (não Escrow!) |
(cobertura no unit test do manager) | (cobertura existente) | ✅ |
GET /v3/payments/{id}/escrow |
✅ | Escrow (id, status enum, expirationDate, finishDate, finishReason enum) |
Escrow/payment-escrow-response.json |
PaymentEscrow_*, EscrowStatus_*, EscrowFinishReason_* (4 tests) |
✅ |
Enum EscrowStatus ACTIVE/DONE |
✅ | enum tipado | inline | EscrowStatus_BothValuesDeserialize |
✅ |
Enum EscrowFinishReason (6 valores) |
✅ | enum tipado | inline | EscrowFinishReason_AllSixValuesDeserialize, _NullWhenStatusActive |
✅ |
| Endpoint | MCP | Model | Fixture | Contract test | Status |
|---|---|---|---|---|---|
POST /v3/pix/automatic/authorizations |
✅ | CreatePixAutomaticAuthorizationRequest + PixAutomaticAuthorization |
PixAutomatic/authorization-create-request-minimal.json, authorization-response.json |
CreateAuthorizationRequest_* (2), AuthorizationResponse_Deserializes* |
✅ |
GET /v3/pix/automatic/authorizations |
✅ | envelope padrão (hasMore/totalCount/limit/offset/data) | PixAutomatic/authorizations-list-response.json |
AuthorizationsListResponse_UsesStandardEnvelopeWithPagination |
✅ |
GET /v3/pix/automatic/authorizations/{id} |
✅ | mesmo PixAutomaticAuthorization |
reusa | (idem) | ✅ |
DELETE /v3/pix/automatic/authorizations/{id} |
✅ | retorna PixAutomaticAuthorization (não envelope deleted) |
reusa | (idem) | ✅ |
GET /v3/pix/automatic/paymentInstructions/{id} |
✅ | PixAutomaticPaymentInstruction (Authorization nested, dueDate, status enum, paymentId, refusalReason) |
PixAutomatic/payment-instruction-response.json |
PaymentInstruction_DeserializesFromOfficialFixture_WithNestedAuthorization |
✅ |
GET /v3/pix/automatic/paymentInstructions (filter) |
✅ | authorizationId/customerId/paymentId/status |
inline | PaymentInstructionListFilter_SerializesAuthorizationIdNotAuthorization |
✅ |
| Enums Status/Frequency/OriginType/PaymentInstructionStatus | ✅ | enums tipados | inline | *_AllFiveValuesDeserialize (3 tests) |
✅ |
Bugs corrigidos nesta fase final:
- B-16:
PixAutomaticPaymentInstructiontinhaAuthorizationcomostring+ campos inventados (Value,PaymentDate,DateCreated,Description). Schema real:Authorizationé objeto aninhado (id/endToEndIdentifier/customerId),DueDate(nãoPaymentDate), +endToEndIdentifier,paymentId,refusalReason. Status virou enumPixAutomaticPaymentInstructionStatus. - B-17:
PixAutomaticPaymentInstructionListFilterusavaauthorization/status. Schema real:authorizationId,customerId,paymentId,status(enum).
| Endpoint | MCP | Model | Fixture | Contract test | Status |
|---|---|---|---|---|---|
GET /v3/pix/transactions/recurrings (envelope padrão) |
✅ | ResponseList<PixRecurringTransaction> (hasMore/totalCount/limit/offset/data) |
PixRecurring/transactions-list-response.json |
TransactionsList_UsesStandardEnvelopeWithPagination |
✅ |
GET /v3/pix/transactions/recurrings (filtros novos) |
✅ | PixRecurringTransactionListFilter (status enum, value decimal invariant, searchText) |
inline | TransactionListFilter_* (4 tests: SerializesAll, InvariantDecimal, UpperEnum, NullOmitted) |
✅ |
GET /v3/pix/transactions/recurrings/{id} |
✅ | PixRecurringTransaction (id, status enum, origin enum, value, frequency enum, quantity, startDate, finishDate, canBeCancelled, externalAccount nested) |
PixRecurring/transaction-response.json |
TransactionResponse_DeserializesFromOfficialFixture |
✅ |
POST /v3/pix/transactions/recurrings/{id}/cancel |
✅ | body vazio → retorna PixRecurringTransaction |
reusa | (cobertura unit do manager) | ✅ |
GET /v3/pix/transactions/recurrings/{id}/items (envelope {data:[...]}) |
✅ | PixRecurringItemsResponse wrapper (sem paginação) |
PixRecurring/items-list-envelope.json |
ItemsListEnvelope_UsesMinimalDataOnlyShape |
✅ |
POST /v3/pix/transactions/recurrings/items/{id}/cancel |
✅ | body vazio → PixRecurringItem (id, status, scheduledDate, canBeCancelled, recurrenceNumber, quantity, value, refusalReasonDescription, externalAccount) |
PixRecurring/item-response.json |
ItemResponse_DeserializesFromOfficialFixture |
✅ |
Enum PixRecurringStatus (5 valores) |
✅ | enum tipado | inline | TransactionStatus_AllFiveValuesDeserialize |
✅ |
Enum PixRecurringFrequency (WEEKLY/MONTHLY) |
✅ | enum tipado | inline | TransactionFrequency_BothValuesDeserialize |
✅ |
Enum PixRecurringOrigin (PIX) |
✅ | enum tipado | inline | TransactionOrigin_PixDeserializes |
✅ |
Enum PixRecurringItemStatus (4 valores) |
✅ | enum tipado | inline | ItemStatus_AllFourValuesDeserialize |
✅ |
Feature nova adicionada nesta fase:
- B-18:
PixRecurringManager.List(offset, limit)não aceitava filtro. O schema oficial expõe três filtros opcionais (status,value,searchText). CriadoPixRecurringTransactionListFilter(request parameters tipado) e novo overloadList(offset, limit, filter). Backwards-compatible:filteré opcional.
Quirks de envelope documentados:
recurrings(transactions list) usa o envelope padrão (hasMore/totalCount/limit/offset/data).recurrings/{id}/itemsusa envelope minimalista{data:[...]}sem paginação — comportamento diferente do schema padrão, mantido emPixRecurringItemsResponsewrapper para evitar deserialização incorreta viaResponseList<T>(regressão B-14 já fixada).
| Endpoint | MCP | Model | Fixture | Contract test | Status |
|---|---|---|---|---|---|
POST /v3/mobilePhoneRecharges (request) |
✅ | CreateMobilePhoneRechargeRequest (value+phoneNumber required) |
MobilePhoneRecharge/create-request.json |
CreateRequest_HasRequiredFields, _NoFakeFields |
✅ |
POST /v3/mobilePhoneRecharges (response) |
✅ | MobilePhoneRecharge (id, value, phoneNumber, status enum, canBeCancelled, operatorName) |
MobilePhoneRecharge/recharge-response.json |
RechargeResponse_DeserializesFromOfficialFixture |
✅ |
GET /v3/mobilePhoneRecharges |
✅ | ResponseList<MobilePhoneRecharge> envelope padrão |
MobilePhoneRecharge/recharges-list-response.json |
RechargesList_UsesStandardEnvelopeWithPagination |
✅ |
GET /v3/mobilePhoneRecharges/{id} |
✅ | mesmo MobilePhoneRecharge |
reusa | (idem) | ✅ |
POST /v3/mobilePhoneRecharges/{id}/cancel |
✅ | body vazio → MobilePhoneRecharge |
(cobertura unit do manager) | (cobertura existente) | ✅ |
GET /v3/mobilePhoneRecharges/{phoneNumber}/provider |
✅ | MobilePhoneProvider (name, values: MobilePhoneProviderValue[] com {name, description, bonus, minValue, maxValue}) |
MobilePhoneRecharge/provider-response.json |
ProviderResponse_DeserializesFromOfficialFixture, _UsesValuesNotAvailableValues |
✅ |
Enum MobilePhoneRechargeStatus (5 valores) |
✅ | enum tipado | inline | RechargeStatus_AllFiveValuesDeserialize |
✅ |
Bug crítico corrigido nesta fase:
- B-19:
MobilePhoneProvidertinhaAvailableValues: List<decimal>(chutado). Schema real:values: arrayde objetosMobilePhoneProviderValuecom campos{name, description, bonus, minValue, maxValue}. Modelo completo reescrito + criada classe novaMobilePhoneProviderValue+ test antigo do manager corrigido (não mais assertaAvailableValues).
Endpoints /v3/myAccount/documents* (5 endpoints). Subgrupo Account Document do MyAccountManager.
| Endpoint | MCP | Model | Fixture | Contract test | Status |
|---|---|---|---|---|---|
GET /v3/myAccount/documents |
✅ | AccountDocumentResponse (envelope {rejectReasons, data:[]} sem paginação) |
AccountDocument/pending-documents-response.json |
PendingDocumentsResponse_DeserializesFromOfficialFixture, _UsesMinimalEnvelopeWithoutPagination |
✅ |
POST /v3/myAccount/documents/{id} (multipart) |
✅ | request UploadAccountDocumentRequest (DocumentFile + Type enum) → response AccountDocument |
AccountDocument/document-response.json |
UploadRequest_HasCorrectMultipartFieldNames |
✅ |
GET /v3/myAccount/documents/files/{id} |
✅ | AccountDocument (id, status enum) |
reusa | DocumentResponse_HasOnlyIdAndStatus |
✅ |
POST /v3/myAccount/documents/files/{id} (multipart update) |
✅ | request UploadAccountDocumentRequest (DocumentFile) → response AccountDocument |
reusa | (idem) | ✅ |
DELETE /v3/myAccount/documents/files/{id} |
✅ | BaseDeleted ({deleted, id}) |
AccountDocument/delete-response.json |
(cobertura unit do manager) | ✅ |
Enum AccountDocumentStatus (4 valores) |
✅ | enum tipado | inline | DocumentStatus_AllFourValuesDeserialize |
✅ |
Enum AccountDocumentGroupStatus (5 valores) |
✅ | enum tipado (Group ganha IGNORED) | inline | DocumentGroupStatus_AllFiveValuesDeserialize |
✅ |
Enum AccountDocumentType (12 valores) |
✅ | enum tipado | inline | DocumentType_AllTwelveValuesDeserialize |
✅ |
Enum AccountDocumentResponsibleType (13 valores) |
✅ | enum tipado | inline | ResponsibleType_AllThirteenValuesDeserialize |
✅ |
Bugs críticos corrigidos nesta fase (B-20):
- B-20a/b/c/d:
AccountDocument.Status,AccountDocumentGroup.Status,AccountDocumentGroup.Type,AccountDocumentResponsible.Typeeramstring/List<string>. Trocados por enums tipados. - B-20f:
AccountDocumentFiletinha campos fictíciosNameeUrl. Schema real retorna apenas{id, status}. Classe removida; endpoints passam a retornar o mesmoAccountDocument. - B-20g:
SubmitDocumentretornavaAccountDocumentGroup. Schema oficial retornaAccountDocumentGetResponseDTO(apenas{id, status}). Tipo de retorno do manager mudado paraAccountDocument. - B-20h:
UploadAccountDocumentRequesttinhaDocumentType: stringeFile: IAsaasFile. Schema espera multipart fieldstypeedocumentFile. Renomeado paraType: AccountDocumentType?eDocumentFile: IAsaasFile, alinhando os nomes após oFirstCharToLowerdoPostMultipartFormDataContentAsync.
Quirk de envelope: /myAccount/documents retorna envelope {rejectReasons, data:[...]} sem hasMore/totalCount/limit/offset. Mantido em AccountDocumentResponse para evitar deserialização incorreta via ResponseList<T> (B-07 já fixado em fase anterior).
| Endpoint | MCP | Model | Fixture | Contract test | Status |
|---|---|---|---|---|---|
POST /v3/invoices (request) |
✅ | CreateInvoiceRequest (required: serviceDescription, observations, value, deductions, effectiveDate, municipalServiceName, taxes; payment/customer/installment opcionais) |
Invoice/schedule-request.json |
CreateRequest_* (3 tests) |
✅ |
POST /v3/invoices (response) |
✅ | Invoice (id, status enum, customer, payment, taxes, etc.) |
Invoice/invoice-response.json |
InvoiceResponse_DeserializesFromOfficialFixture, TaxesResponse_HasAllReformaTributariaFields |
✅ |
GET /v3/invoices (filtros) |
✅ | InvoiceListFilter (effectiveDate[Ge]/[Le], payment, installment, customer, externalReference, status) |
inline | ListFilter_UsesCapitalGeAndLeForEffectiveDate, _SupportsCustomerAndExternalReference |
✅ |
GET /v3/invoices/{id} |
✅ | mesmo Invoice |
reusa | (idem) | ✅ |
PUT /v3/invoices/{id} |
✅ | UpdateInvoiceRequest (todos opcionais + updatePayment) |
inline | UpdateRequest_SupportsUpdatePaymentFlag |
✅ |
POST /v3/invoices/{id}/authorize |
✅ | body vazio → Invoice |
(cobertura unit do manager) | (cobertura existente) | ✅ |
POST /v3/invoices/{id}/cancel |
✅ | body vazio → Invoice |
(cobertura unit do manager) | (cobertura existente) | ✅ |
Enum InvoiceStatus (6 valores) |
✅ | enum tipado | inline | InvoiceStatus_AllSixValuesDeserialize |
✅ |
Bugs corrigidos nesta fase (B-21):
- B-21a:
Taxesmodel só tinha 7 campos (retainIss, iss, cofins, csll, inss, ir, pis). SchemaInvoiceTaxesResponseDTOtem mais 6 (nbsCode, taxSituationCode, taxClassificationCode, operationIndicatorCode, pisCofinsRetentionType, pisCofinsTaxStatus) + 6 da Reforma Tributária (stateIbs, stateIbsValue, municipalIbs, municipalIbsValue, cbs, cbsValue) → todos esses sumiam silenciosamente. Modelo expandido para 19 campos. - B-21b:
InvoiceListFilterusavaeffectiveDate[ge]e[le]lowercase. Schema oficial usa[Ge]e[Le]maiúsculos. O filtro com casing errado era silenciosamente ignorado pela API. - B-21c:
InvoiceListFilterfaltavacustomereexternalReference. Adicionados. - B-21d:
CreateInvoiceRequesteUpdateInvoiceRequestfaltavamupdatePayment: bool?. Adicionado em ambos.
| Endpoint | MCP | Model | Fixture | Contract test | Status |
|---|---|---|---|---|---|
POST /v3/paymentDunnings (multipart) |
✅ | CreatePaymentDunningRequest (9 campos obrigatórios + documents binários) |
(cobertura unit do manager) | CreateRequest_UsesPaymentNotPaymentId |
✅ |
POST /v3/paymentDunnings (response) |
✅ | PaymentDunning (id, dunningNumber int?, status enum, type enum, payment, requestDate, value, feeValue, netValue, canBeCancelled bool?, isNecessaryResendDocumentation bool?, cannotBeCancelledReason, denialReason) |
PaymentDunning/dunning-response.json |
DunningResponse_* (2 tests) |
✅ |
GET /v3/paymentDunnings |
✅ | ResponseList<PaymentDunning> + PaymentDunningListFilter (status, type, payment, requestStartDate, requestEndDate) |
PaymentDunning/dunnings-list-response.json |
DunningsList_*, ListFilter_* |
✅ |
GET /v3/paymentDunnings/{id} |
✅ | mesmo PaymentDunning |
reusa | (idem) | ✅ |
POST /v3/paymentDunnings/simulate |
✅ | payment como QUERY param, body vazio → SimulatedPaymentDunning com TypeSimulations: List<...> |
PaymentDunning/simulate-response.json |
SimulateResponse_DeserializesFromOfficialFixture |
✅ |
GET /v3/paymentDunnings/{id}/history |
✅ | ResponseList<PaymentDunningEventHistory> com Status: PaymentDunningHistoryStatus enum |
PaymentDunning/history-list-response.json |
HistoryResponse_*, HistoryStatus_AllFourValuesDeserialize |
✅ |
GET /v3/paymentDunnings/{id}/partialPayments |
✅ | ResponseList<PaymentDunningPartialPayments> (value, description, paymentDate) |
PaymentDunning/partial-payments-response.json |
PartialPaymentsResponse_DeserializesFromOfficialFixture |
✅ |
GET /v3/paymentDunnings/paymentsAvailableForDunning |
✅ | ResponseList<PaymentDunningPaymentAvailable> com TypeSimulations: List<...> |
PaymentDunning/payments-available-response.json |
PaymentsAvailableResponse_DeserializesFromOfficialFixture |
✅ |
POST /v3/paymentDunnings/{id}/cancel |
✅ | body vazio → PaymentDunning |
(cobertura unit do manager) | (cobertura existente) | ✅ |
Enum PaymentDunningStatus (8 valores) |
✅ | enum tipado | inline | DunningStatus_AllEightValuesDeserialize |
✅ |
Enum PaymentDunningType (CREDIT_BUREAU + DEBT_RECOVERY_ASSISTANCE p/ filter) |
✅ | enum tipado | inline | DunningType_BothValuesDeserialize |
✅ |
Enum PaymentDunningHistoryStatus (4 valores) |
✅ | enum tipado | inline | HistoryStatus_AllFourValuesDeserialize |
✅ |
Bugs corrigidos nesta fase (B-22):
- B-22a:
PaymentDunning.DunningNumbererastring. Schema éinteger(int32). Trocado paraint?. - B-22b:
PaymentDunningfaltavaCannotBeCancelledReason: string. Adicionado. - B-22c/d:
PaymentDunning.CanBeCancelledeIsNecessaryResendDocumentationeramboolnon-nullable. Schema permite null. Trocados parabool?. Sem o fix, omitir esses campos no JSON forçavafalsesilenciosamente. - B-22e:
PaymentDunning.ReceivedInCashFeeValueeCancellationFeeValuemarcados como[Obsolete](schema oficial marca deprecated). - B-22f:
PaymentDunningEventHistory.Statuserastring. Schema é enumPaymentDunningHistoryStatus(IN_NEGOTIATION, NEGOTIATION_FAIL, NEGOTIATED, PAID). Trocado para enum tipado. - B-22h:
PaymentDunningTypeenum tinha apenasCREDIT_BUREAU. Filter aceita tambémDEBT_RECOVERY_ASSISTANCE. Adicionado. - B-22k:
Simulate(request)enviavapaymentno body JSON. Schema oficial expõe como query param (?payment=pay_xxx) e exige body vazio. Manager corrigido para construir query string. - B-22m:
SimulatedPaymentDunning.TypeSimulationsePaymentDunningPaymentAvailable.TypeSimulationseram objeto único. Schema retorna ARRAY. Trocados paraList<PaymentDunningTypeSimulations>. Sem o fix, deserialização lançavaInvalidCastExceptionno JSON real.
| Endpoint | MCP | Model | Fixture | Contract test | Status |
|---|---|---|---|---|---|
POST /v3/creditBureauReport (request) |
✅ | CreateCreditBureauReportRequest (customer? + cpfCnpj? — ambos opcionais) |
inline | CreateRequest_HasOnlyCustomerAndCpfCnpj, _DoesNotSerializeRemovedFields |
✅ |
POST /v3/creditBureauReport (response) |
✅ | CreditBureauReport (id, dateCreated, cpfCnpj, customer, downloadUrl, reportFile) — reportFile populado APENAS no POST |
CreditBureauReport/report-create-response.json |
ReportResponse_PopulatesReportFile_OnCreate |
✅ |
GET /v3/creditBureauReport |
✅ | ResponseList<CreditBureauReport> + CreditBureauReportListFilter (startDate, endDate) |
CreditBureauReport/reports-list-response.json |
ReportsList_*, ListFilter_* (2 tests) |
✅ |
GET /v3/creditBureauReport/{id} |
✅ | mesmo CreditBureauReport (mas reportFile=null aqui) |
CreditBureauReport/report-response.json |
ReportResponse_DeserializesFromOfficialFixture_GetById, _NoFakeFields |
✅ |
Bugs corrigidos nesta fase (B-23):
- B-23a/b:
CreditBureauReporttinhaState: stringeStatus: string— nenhum existe no schema oficial. Removidos. Era chute do dev original. - B-23c:
CreditBureauReportfaltavaDownloadUrl: stringeReportFile: string(PDF Base64). Adicionados. Sem o fix, consumidores não tinham como baixar o relatório. - B-23d:
CreateCreditBureauReportRequest.Statefoi removido (não existe no schema). - B-23e:
List(offset, limit)não aceitava filtro. Schema expõestartDateeendDate. CriadoCreditBureauReportListFiltere novo overloadList(offset, limit, filter)backwards-compatible.
| Endpoint | MCP | Model | Fixture | Contract test | Status |
|---|---|---|---|---|---|
POST /v3/bill (request) |
✅ | CreateBillPaymentRequest (required: identificationField; opcionais: scheduleDate, description, discount, interest, fine, dueDate, value, externalReference) |
inline | CreateRequest_SerializesAllKeysIncludingNewOnes, _OptionalFieldsOmittedWhenNull |
✅ |
POST /v3/bill (response) |
✅ | BillPayment (17 campos incluindo interest, fine, paymentDate, externalReference, failReasons array) |
BillPayment/bill-response.json |
BillResponse_DeserializesFromOfficialFixture, _FailReasonsIsArrayOfStrings |
✅ |
GET /v3/bill |
✅ | ResponseList<BillPayment> |
BillPayment/bills-list-response.json |
BillsList_UsesStandardEnvelopeWithPagination |
✅ |
GET /v3/bill/{id} |
✅ | mesmo BillPayment |
reusa | (idem) | ✅ |
POST /v3/bill/simulate (request) |
✅ | SimulateBillPaymentRequest (identificationField OU barCode) |
inline | SimulateRequest_AcceptsIdentificationFieldOrBarCode |
✅ |
POST /v3/bill/simulate (response) |
✅ | SimulatedBillPayment (minimumScheduleDate, fee, bankSlipInfo com 17 campos) |
BillPayment/simulate-response.json |
SimulateResponse_DeserializesFromOfficialFixture |
✅ |
POST /v3/bill/{id}/cancel |
✅ | body vazio → BillPayment |
(cobertura unit do manager) | (cobertura existente) | ✅ |
Enum BillPaymentStatus (7 valores) |
✅ | enum tipado | inline | BillStatus_AllSevenValuesDeserialize |
✅ |
Bugs corrigidos nesta fase (B-24):
- B-24a:
BillPaymentfaltavaInterest,Fine,PaymentDate,ExternalReference.FailReasonserastring; schema éarray of string— trocado paraList<string>. - B-24b:
BillPaymentStatusenum tinha apenas 5 valores. Schema tem 7 (adicionadosREFUNDEDeAWAITING_CHECKOUT_RISK_ANALYSIS_REQUEST). - B-24c:
BillPayment.CanBeCancelled/DueDate/ScheduleDate/PaymentDateagora são nullable (response pode omitir/null em status iniciais). - B-24d:
CreateBillPaymentRequestfaltavaInterest,Fine,ExternalReference. Campos não-obrigatórios (Value,DueDate,ScheduleDate,Discount) trocados para nullable (apenasIdentificationFieldé required no schema). - B-24e:
BankSlipInfotinha 5 campos comBankCode(nome chutado). Schema tem 17 campos combank. Modelo reescrito:Bank,BeneficiaryCpfCnpj,BeneficiaryName,AllowChangeValue,MinValue,MaxValue,DiscountValue,InterestValue,FineValue,OriginalValue,TotalDiscountValue,TotalAdditionalValue,IsOverdue— todos adicionados.
| Endpoint | MCP | Bugs corrigidos |
|---|---|---|
POST /v3/customers (CRUD) |
✅ | B-25e (NotificationDisabled bool? em Create/Update) |
GET /v3/customers + 5 filtros |
✅ | OK |
GET /v3/customers/{id} |
✅ | B-25a (DateCreated nullable) |
PUT /v3/customers/{id} |
✅ | (idem create) |
DELETE /v3/customers/{id} + restore |
✅ | OK |
GET /v3/customers/{id}/notifications |
✅ | B-25g — endpoint estava faltando no manager. Adicionado GetNotifications |
Contract tests: CustomerContractTests (8 tests).
Cobre todos os endpoints alem de /limits e /simulate (já em §1).
| Endpoint | MCP | Bugs corrigidos |
|---|---|---|
POST /v3/payments (BOLETO/PIX/etc) |
✅ | OK |
POST /v3/payments/ (Credit Card) |
✅ | OK |
GET /v3/payments com 18 filtros |
✅ | B-26d — faltavam 9 filtros: customerGroupName, invoiceStatus, estimatedCreditDate, pixQrCodeId, anticipable, user, checkoutSession, dateCreated[ge]/[le], estimatedCreditDate[ge]/[le] |
GET /v3/payments/{id} |
✅ | B-26a/b/c (DateCreated, DueDate, OriginalDueDate nullable) |
PUT/DELETE/POST restore/refund/... |
✅ | OK |
GET /v3/payments/{id}/pixQrCode |
✅ | OK |
GET /v3/payments/{id}/identificationField |
✅ | OK |
POST /v3/payments/{id}/receiveInCash |
✅ | OK |
Quirk: filtro Payment usa [ge]/[le] lowercase (Invoice usa [Ge]/[Le] uppercase).
Contract tests: PaymentContractTests (21 tests: 6 existentes + 7 novos do resto).
| Endpoint | MCP | Bugs corrigidos |
|---|---|---|
POST /v3/subscriptions + List/Find/Update/Delete |
✅ | B-27d (Object, PaymentLinkId, CheckoutSession, Split adicionados) |
PUT /v3/subscriptions/{id}/creditCard |
✅ | OK |
GET /v3/subscriptions/{id}/payments + /paymentBook |
✅ | OK |
POST/PUT/GET/DELETE /v3/subscriptions/{id}/invoiceSettings |
✅ | OK |
GET /v3/subscriptions/{id}/invoices |
✅ | OK |
Bugs:
- B-27a: enum
SubscriptionStatusfaltavaINACTIVE(tinha apenas ACTIVE/EXPIRED). - B-27b/c:
DateCreated,NextDueDate→ DateTime? - B-27e: filter faltava
customerGroupName,status,deletedOnly,externalReference,order,sort.
Contract tests: SubscriptionContractTests (5 tests).
| Endpoint | MCP | Bugs corrigidos |
|---|---|---|
POST/GET/DELETE /v3/pix/addressKeys |
✅ | B-28c (Status enum, QrCode nested, CanBeDeleted/Reason) |
POST /v3/pix/qrCodes/static + DELETE |
✅ | OK |
GET /v3/pix/tokenBucket/addressKey |
✅ | OK |
POST /v3/pix/qrCodes/pay + /decode |
✅ | OK |
GET /v3/pix/transactions com 3 filtros |
✅ | B-28e — filter não existia. Criado PixTransactionListFilter |
GET /v3/pix/transactions/{id} |
✅ | B-28b — modelo reescrito (7 → 25 campos) |
POST /v3/pix/transactions/{id}/cancel |
✅ | OK |
Bug crítico B-28a: PixTransactionStatus enum estava com 5 valores INVENTADOS (PENDING, FAILED não existem no schema). Reescrito com 11 valores reais.
Novos enums: PixTransactionType (5), PixTransactionOriginType (6), PixTransactionFinality (2), PixAddressKeyStatus (6).
Contract tests: PixContractTests (7 tests).
| Endpoint | MCP | Bugs corrigidos |
|---|---|---|
POST /v3/transfers (bank account) |
✅ | OK |
POST /v3/transfers/ (asaas account) |
✅ | OK |
GET /v3/transfers com 5 filtros |
✅ | B-29h — faltavam dateCreated[ge]/[le] e transferDate[ge]/[le] |
GET /v3/transfers/{id} |
✅ | B-29b/c (DateCreated, Authorized nullable) |
DELETE /v3/transfers/{id}/cancel |
✅ | OK |
Bugs: B-29d (AsaasAccountTransferStatus faltavam BANK_PROCESSING/FAILED), B-29e (novo enum TransferOperationType), B-29g (BaseTransfer faltava 7 campos), Bank/BankAccount faltavam vários campos.
Contract tests: TransferContractTests (5 tests).
Endpoints: POST/GET /v3/anticipations, simulate, find, cancel, limits, automatic configurations.
Bugs B-30: Anticipation.AnticipationDate/DueDate/RequestDate → DateTime? + campo Object adicionado.
Contract tests: AnticipationContractTests (3 tests).
Endpoints: POST/GET/PUT/DELETE /v3/installments, refund, payments, paymentBook, cancelPendingPayments, splits.
Bugs B-31: ExpirationDay → int?, adicionados CreditCard (nested) e Refunds (array).
Contract tests: InstallmentContractTests (2 tests).
Endpoints: POST/GET/PUT/DELETE /v3/webhooks, removeBackoff.
Sem bugs estruturais. Modelo Webhook + enum WebhookEvent (110+ valores) verificados OK.
Quirk: GET /v3/webhooks no schema só aceita offset/limit (filter WebhookListFilter mantido por backwards-compat — backend pode aceitar mesmo não documentado).
Contract tests: WebhookContractTests (3 tests).
Endpoint único: GET /v3/wallets/.
Bug B-33: Wallet faltava Object (response wrapper). Adicionado.
Contract tests: WalletContractTests (1 test).
| Endpoint | MCP | Bugs corrigidos |
|---|---|---|
PUT /v3/notifications/{id} |
✅ | B-34b (todos bools → bool? em UpdateRequest) |
PUT /v3/notifications/batch |
✅ | OK |
Bugs: B-34a (Event enum faltando — novo NotificationEvent 6 valores), B-34b (Notification + UpdateRequest com bools nullable).
Contract tests: NotificationContractTests (3 tests).
| Endpoint | MCP | Bugs corrigidos |
|---|---|---|
POST /v3/creditCard/tokenizeCreditCard |
✅ | B-35a (Brand string → enum CreditCardBrand 13 valores) |
POST /v3/creditCard/preAuthorization/config |
✅ | B-35b — PreAuthorizationConfig tinha campos INVENTADOS (Enabled, AutomaticCaptureDelay). Schema: {daysToExpire}. Reescrito |
GET /v3/creditCard/preAuthorization/config |
✅ | (idem) |
Contract tests: CreditCardContractTests (5 tests).
11 endpoints (CRUD + images).
Bugs B-36:
- B-36a: PaymentLink.SubscriptionCycle string →
Cycleenum (7 valores). - B-36b: faltavam ViewCount, IsAddressRequired, ExternalReference.
- B-36c: Value, Active, NotificationEnabled, Deleted, DueDateLimitDays, MaxInstallmentCount → nullable.
Contract tests: PaymentLinkContractTests (3 tests).
| Endpoint | MCP | Bugs corrigidos |
|---|---|---|
GET /v3/finance/balance |
✅ | OK |
GET /v3/finance/payment/statistics |
✅ | B-37b — não aceitava filtros. Schema expõe 11. Criado PaymentStatisticsFilter |
GET /v3/finance/split/statistics |
✅ | B-37a — campos INVENTADOS (TotalPendingValue/TotalReceivedValue). Schema: {income, value}. Reescrito |
/v3/financialTransactions (legado, fora do schema) |
mantido por backwards-compat |
Contract tests: FinanceContractTests (4 tests).
Endpoints /myAccount/commercialInfo, /status, /fees, /accountNumber, /paymentCheckoutConfig, DELETE /myAccount.
Bugs B-38:
- B-38a: MyAccount.Status string →
AccountInfoStatusenum (4 valores). - B-38b: faltavam CompanyName, IncomeValue, TradingName, Site, AvailableCompanyNames (array), CommercialInfoExpiration (nested).
- InscricaoEstadual marcado
[Obsolete](não existe no schema atual).
Contract tests: MyAccountContractTests (3 tests).
Endpoints: POST/GET /v3/accounts, find, resendActivationLink, accessTokens CRUD.
Bugs B-39:
- B-39a: Account.City string →
long?(schema: integer city id). - B-39b: faltavam Object, Id, BirthDate, TradingName, Site, AccountNumber (nested), CommercialInfoExpiration (nested).
- B-39c: ApiKey marcado
[Obsolete](não existe no schema oficial).
Contract tests: AsaasAccountContractTests (1 test).
10 endpoints (CRUD + lookups municipais/federais/nbs/tributários).
Bugs B-40:
- B-40a: faltava NbsCode.
- B-40b: RpsNumber, LoteNumber string → int (schema: integer).
- B-40c: faltavam PasswordSent, AccessTokenSent, CertificateSent (bools) + NationalPortalTaxCalculationRegime + Object.
- B-40d/e: StateInscription e AccessToken marcados
[Obsolete].
Contract tests: FiscalInfoContractTests (1 test).
Endpoints: GET list/find, POST dispute.
Bug B-41: Chargeback faltava CreditCard (nested ChargebackCreditCard com number + brand enum). Reason → nullable.
Contract tests: ChargebackContractTests (3 tests).
3 endpoints (approve account, confirm payment, force overdue).
Sem bugs — manager já correto. EnsureSandbox() bloqueia uso em produção.
Contract tests: SandboxContractTests (1 test sanity check).
Padrões de bug encontrados em múltiplos managers e como foram corrigidos sistemicamente:
- Endpoints afetados:
GET /myAccount/documents(§7),GET /pix/transactions/recurrings/{id}/items(§5). - Anti-padrão: Usar
ResponseList<T>que assumehasMore/totalCount/limit/offset. - Fix: wrapper dedicado (
AccountDocumentResponse,PixRecurringItemsResponse).
- Solução sistêmica:
RequestParameters.Add(bool?)força lowercase"true"/"false". - Coberto por:
RequestParametersContractTests.Bool_*(3 tests, 2026-05-24). - Validado em runtime:
PaymentIntegrationTests.ListPayments_WithAnticipatedFilter(§99).
- Padrão Asaas: Payment usa
[ge]/[le]LOWERCASE; Invoice usa[Ge]/[Le]UPPERCASE. - Bugs corrigidos: B-21b (Invoice), B-29h (Transfer), B-26d (Payment já estava correto).
- Validado: contract tests +
TransferIntegrationTests.ListTransfers_WithDateRangeFilter.
- Bug crítico B-22k:
POST /paymentDunnings/simulateenviavapaymentno body. Schema oficial expõe como query param. - Fix:
PaymentDunningManager.Simulateconstrói query string e envia body vazio.
- Bugs corrigidos:
- B-19 (
MobilePhoneProvider.AvailableValueseraList<decimal>— schema: array de{name, description, bonus, minValue, maxValue}) - B-20a–d (4 enums tipados em AccountDocument)
- B-22f (
PaymentDunningHistoryStatus), B-22h (PaymentDunningType ganhou DEBT_RECOVERY_ASSISTANCE) - B-24b (
BillPaymentStatus5→7 valores), B-27a (SubscriptionStatusganhou INACTIVE) - B-28a (
PixTransactionStatus5 valores INVENTADOS → 11 reais — mais grave) - B-34a (
NotificationEventenum criado), B-35a (CreditCardBrand), B-36a (Cycle) - B-38a (
AccountInfoStatus), B-40b (Rps/Lote int), B-41 (Chargeback enums)
- B-19 (
- Bug B-22m:
SimulatedPaymentDunning.TypeSimulationsePaymentDunningPaymentAvailable.TypeSimulationseram objeto único. Schema retorna array. LançavaInvalidCastExceptionem runtime.
- Bugs corrigidos: B-22c/d, B-26a/b/c, B-27b/c, B-29b/c, B-30a, B-34b, B-35, B-36c, B-25a/e. Sempre que schema permite omitir/null, mas modelo era non-nullable, deserialização quebrava ou forçava
false/defaultsilenciosamente.
- Validada via
ResponseList<T>envelope padrão em todos os contract tests*List_UsesStandardEnvelopeWithPagination.
- Bugs: B-21d (UpdatePayment em Invoice), B-24d (Interest/Fine/ExternalReference em BillPayment), B-25g (GetNotifications endpoint), B-28e/B-37b (filtros faltando).
- Bugs: B-17 (
authorization→authorizationId), B-29 (bankCode→bank), B-21b ([ge]/[le] casing), B-22a (DunningNumber int vs string), B-40b (RpsNumber int vs string).
- Bugs graves: B-23a/b (
State,Statusem CreditBureauReport), B-20f (Name,Urlem AccountDocumentFile), B-35b (Enabled,AutomaticCaptureDelayem PreAuthorizationConfig), B-37a (TotalPendingValue,TotalReceivedValueem SplitStatistics), B-39 (ApiKey,Citystring em Account), B-40 (StateInscription,AccessTokenem FiscalInfo). - Estes representam pura chute do dev original sem verificar a doc. Removidos ou marcados
[Obsolete].
RequestParameters.Add(decimal?)comInvariantCulture(12.5não12,5).RequestParameters.Add(bool?)com lowercase.DateTimeExtensions.ToApiRequestcomInvariantCulture.RequestParameters.Add(Enum)serializa nome do enum em UPPER.- Envelope padrão
{object, hasMore, totalCount, limit, offset, data}emResponseList<T>.
Status: ✅ implementado — 15 tests cobrindo 7 managers críticos. Skip automático sem ASAAS_SANDBOX_TOKEN.
| Manager | Tests | Endpoints cobertos | Valida regression |
|---|---|---|---|
| Customer | 2 | CRUD completo + List paginado | Round-trip, envelope padrão |
| Payment | 3 | POST BOLETO/PIX, GET pixQrCode, List filter Anticipated | B-26d (bool? filter) |
| Subscription | 2 | Create BOLETO + List filter Status=INACTIVE | B-27a (enum INACTIVE) |
| Pix | 2 | ListAddressKeys, ListTransactions filter Status=AWAITING_REQUEST | B-28a (enum 11 valores) |
| Transfer | 1 | List filter date range [ge]/[le] | B-29h (casing lowercase) |
| Anticipation | 2 | List + GetLimits | Envelope, schema |
| Finance | 3 | Balance + Statistics filter + Split shape | B-37a (income/value), B-37b (filter) |
Infraestrutura:
[IntegrationFact](custom attribute) — skip automático seASAAS_SANDBOX_TOKENausente, mensagem explicativa no skip reason.IntegrationTestBase—[Trait("Category", "Integration")], constróiAsaasApireal apontando paraAsaasEnvironment.SANDBOX.- Cada test cria seus próprios recursos (suffix timestampado) e limpa no
finallypara não poluir o sandbox.
CI workflow: .github/workflows/integration-sandbox.yml
workflow_dispatch(trigger manual via UI do GitHub)schedule: '0 4 * * *'(nightly 04:00 UTC / 01:00 BRT)- Secret necessário:
ASAAS_SANDBOX_TOKEN(Settings → Secrets and variables → Actions) - Workflow emite warning explícito se secret estiver ausente, mas não falha.
Para rodar localmente:
$env:ASAAS_SANDBOX_TOKEN = "aact_YTU0...seu_token_sandbox..."
dotnet test --filter "Category=Integration"Para rodar tudo EXCETO integration (CI local sem credencial):
dotnet test --filter "Category!=Integration"Sem a variável: integration tests fazem skip automaticamente — dotnet test continua verde.
Cada integration test foi escrito seguindo este checklist:
- ✅ Cria seus próprios recursos (não depende de estado pré-existente no sandbox)
- ✅ Usa timestamp no nome/email para evitar colisão entre execuções
- ✅ Limpa recursos no
finallyquando aplicável - ✅ Asserta
WasSuccessful()com mensagem de erro detalhada (para diagnóstico no CI) - ✅ Valida pelo menos um bug específico (B-XX) corrigido na auditoria
- ✅ Não duplica cobertura de contract tests (foca em comportamento end-to-end, não shape)
Status: AINDA NÃO EXECUTADOS contra sandbox real nesta sessão — apenas escritos e validados que skip funciona. O agente que escreveu a auditoria não tem acesso a ASAAS_SANDBOX_TOKEN. Para fechar essa lacuna:
- Curto prazo: rodar manualmente via
workflow_dispatchno GitHub Actions com o secret configurado. Resultado da primeira execução pode revelar:- Schemas de fixture incompletos (raros, mas possíveis)
- Comportamentos sandbox vs spec divergentes
- Algum CPF de teste rejeitado pelo sandbox específico
- Médio prazo: expandir cobertura conforme bugs surgirem em produção dos consumidores.
| Padrão | Status | Onde |
|---|---|---|
Query params bool serializa lowercase true/false |
✅ | RequestParameters.Add(bool?) + RequestParametersContractTests.Bool_* (3 tests) |
| Query params decimal serializa invariant culture (ponto, não vírgula) | ✅ | RequestParameters.Add(decimal?) + Decimal_SerializesWithDotInAllCultures (4 culturas) |
Query params DateTime serializa YYYY-MM-DD em qualquer cultura |
✅ | DateTimeExtensions.ToApiRequest + DateTime_SerializesAsIsoYyyyMmDdInAllCultures (3 culturas) |
| Query params enum serializa nome do enum em UPPER | ✅ | RequestParameters.Add(Enum) + Enum_SerializesAsUppercaseAsaasName |
| Query string escapa caracteres especiais | ✅ | Build_BuildsCorrectQueryStringWithEscaping |
Envelope {data:[...]} (sem hasMore) — endpoints conhecidos |
✅ | AccountDocument (B-07 fixado), PixRecurring.ListItems (B-14 fixado) |
bool? em campos opcionais de response |
⏳ | grep durante Fase 5 |
Lista honesta do que não está 100% fechado, classificada por aceitabilidade:
Nenhum. Todos os 27 managers passaram por auditoria schema-first.
1. Integration tests nunca rodaram contra sandbox real nesta sessão. ✅ RESOLVIDO
- Primeira execução real: run #26378491985 em 2026-05-25.
- Resultado: 15/15 testes passaram em 6.7s contra
api-sandbox.asaas.com. - Validou em runtime real: B-26d (bool filter lowercase), B-27a (SubscriptionStatus.INACTIVE), B-28a (PixTransactionStatus enum 11 valores), B-29h (TransferListFilter date range casing), B-37a (SplitStatistics shape income/value), B-37b (PaymentStatisticsFilter), entre outros.
- Nightly run configurado em
integration-sandbox.ymlcontinua valendo para regressões futuras.
2. Algumas fixtures foram escritas manualmente a partir dos exemplos MCP (não auto-geradas).
- Risco: se eu copiei mal um exemplo (ex: esqueci um campo que aparece em outros casos), o contract test passa mas o modelo continua incompleto.
- Mitigação:
JsonContractAssert.HasRootProperty+DoesNotSerializeKeyem campos críticos detectam divergência. - Lacunas conhecidas: enums com 100+ valores (WebhookEvent) só testam 10 representativos.
Endpoints /financialTransactions (FinanceManager): legado, não está mais no MCP. Mantido por backwards-compat.
Webhooks (recebimento de payloads): O SDK expõe WebhookManager para configurar endpoints, mas não decodificadores tipados dos payloads que o Asaas envia. Consumidores deserializam manualmente. Scope decisão: seria um SDK separado.
Reforma Tributária: Campos stateIbs/municipalIbs/cbs em Taxes (Invoice) adicionados conforme spec atual. Comportamento em produção depende do calendário de implementação. Pode mudar — auditar quando spec mudar.
Campos [Obsolete]: 5 campos marcados em PaymentDunning, AsaasAccount, FiscalInfo, MyAccount. Mantidos por backwards-compat. Backend pode parar de retornar a qualquer momento — consumidores devem migrar.
Filtros WebhookListFilter (name, enabled, interrupted): Não documentados no MCP, mas mantidos no SDK porque a API original aceita. Se falhar, remover.
Endpoint adicional FiscalInfo: 6 endpoints de lookup (federalServiceCodes, nbsCodes, operationIndicatorCodes, taxClassificationCodes, taxSituationCodes, nationalPortal) existem no schema mas não no manager. Decisão: feature adicional, não impede uso do SDK.