Skip to content
Last updated

Read this page if you already integrate with the API v2 and your code handles Cash-Outs, Cash-Ins, webhooks or error responses. It lists what changed in v2.2 and what to change in your code. The full list of changes is in the Changelog.

What does not change:

  • URLs — the same base URLs and the same endpoints.
  • Authentication — the same POST /auth/token, Authorization, ApplicationToken and DigitalSignature.
  • Webhook event names — CASHIN_* and CASHOUT_* keep their names, including CASHIN_REQUESTED, CASHOUT_REQUESTED and CASHOUT_FAILED. What changes is the data inside some of them.

Breaking changes

In the tables below, Before is what v2.1 returned or documented, and After is the v2.2 contract.

Cash-Out

FieldBefore (v2.1)After (v2.2)
status — paidPAID (and COMPLETED, documented as a legacy synonym)COMPLETED
status — money never leftFAILEDCANCELLED
status — held on the ConnectPSP sideANALYSING could appearPENDING
status — full listPROCESSING, PENDING, PAID, FAILED, REFUNDED, CANCELLED, COMPLETEDPROCESSING, PENDING, COMPLETED, CANCELLED, REFUNDED
Payment datepaidAtcompletedAt
Failure datefailedAtRemoved. A cancelled Cash-Out carries cancelledAt
Cancellation datecanceledAt (one L)cancelledAt (two L, like the CANCELLED status)
failureOn FAILEDOnly on CANCELLED
failure.codeREJECTED or GENERIC_ERROROne code from a fixed catalog of 18 codes — see the failure.code table
failure.messageFree text, in PortugueseFixed per code, in English
reasonFree textA code, only on REFUNDED: PAYEE_REQUESTED, FRAUD, OPERATIONAL_ERROR, REVERSED_BY_INSTITUTION or OTHER
payee.destination.pixKeyType"CPF/CNPJ" for a document keyCPF or CNPJ. The full list is CPF, CNPJ, EMAIL, PHONE, EVP
Insufficient balance on POST /cash-out422 with code: "INSUFFICIENT_FUNDS"202 Accepted, then CASHOUT_FAILED with failure.code: "INSUFFICIENT_FUNDS". Never a 422
externalReference maximum length100 characters (documented)50 characters

The rule behind the statuses: if the money never left your account, it is CANCELLED; if it left and came back, it is REFUNDED.

Cash-In

FieldBefore (v2.1)After (v2.2)
Cancellation datecanceledAt (one L)cancelledAt (two L). CANCELLED is now documented on GET /cash-in/{id}
reasonNot returnedA code, only on REFUNDED: FRAUD, DUPLICATED_PAYMENT, CUSTOMER_REQUEST, MERCHANT_ERROR, PAYER_NOT_ALLOWED or OTHER
externalReference maximum length100 characters (documented)50 characters

Webhooks

EventBefore (v2.1)After (v2.2)
CASHIN_REQUESTEDdata.status: "REQUESTED"data.status: "AWAITING_PAYMENT", as on POST /cash-in and GET /cash-in/{id}
CASHOUT_REQUESTEDdata.status: "REQUESTED"data.status: "PROCESSING", as on POST /cash-out and GET /cash-out/{id}
CASHOUT_COMPLETEDdata.status: "COMPLETED", completedAtNo change in these fields — GET /cash-out/{id} now uses them too. Adds settlement
CASHOUT_FAILEDdata.status: "FAILED", failure.code REJECTED / GENERIC_ERROR, failedAtSame event name. data.status: "CANCELLED", failure from the catalog, cancelledAt
CASHOUT_REFUNDEDreason as free textreason as a code. Adds settlement
CASHIN_REFUNDEDNo reasonreason as a code

Every Cash-Out field change in the table above applies to the webhooks too: webhook data is the same object as GET /cash-out/{id}.

Errors

CaseBefore (v2.1 documentation)After (v2.2)
Wrong credentials on POST /auth/token401 INVALID_CREDENTIALS401 with { "message": "..." }, a plain object with no code
JWT expired401 TOKEN_EXPIRED401 with no body and a WWW-Authenticate header (error_description="The token expired at '...'"). Request a new token
JWT missing or invalid401401 with no body and a WWW-Authenticate header
ApplicationToken missing or invalid401 INVALID_APPLICATION_TOKEN401 Problem Details with no code; tell the cases apart by title
DigitalSignature missing or wrong422 INVALID_SIGNATURE401 DIGITAL_SIGNATURE_REQUIRED or 401 DIGITAL_SIGNATURE_INVALID; 403 CRYPTO_TOKEN_NOT_CONFIGURED when your client has no CryptoToken
Insufficient balance on POST /cash-out422 INSUFFICIENT_FUNDSNot an HTTP error: CASHOUT_FAILED with failure.code: "INSUFFICIENT_FUNDS"
PIX key not found on POST /cash-out422 PIX_KEY_NOT_FOUNDNot an HTTP error: CASHOUT_FAILED with failure.code: "PIX_KEY_NOT_FOUND"
Transaction not found404 NOT_FOUND404 CASHIN_NOT_FOUND or 404 CASHOUT_NOT_FOUND
Refund of a Cash-In that cannot be refunded422 CASH_IN_NOT_PAID, CASH_IN_ALREADY_REFUNDED, CASH_IN_EXPIRED, CASH_IN_CANCELLED422 REFUND_NOT_ALLOWED; detail says which case
Refund before the payment E2E is available422 MISSING_END_TO_END_ID422 MISSING_E2E

The authentication errors are described in Authentication Errors.

Summary

GET /cash-out/summary:

BucketBefore (v2.1)After (v2.2)
Paidtotals.paidtotals.completed
Failedtotals.failedRemoved. Counted under totals.cancelled
Full list of keysprocessing, pending, paid, failed, refunded, cancelledprocessing, pending, completed, cancelled, refunded — the Cash-Out statuses in lowercase
settlementPaid transactionscompleted only

GET /cash-in/summary does not change: the Cash-In paid bucket is still paid. The reconciliation formula becomes cashOut.totals.completed.amount where it used cashOut.totals.paid.amount — see Reconciliation.


Behavior changes

These do not break a correct integration, but you may see different values than before.

  • expiredAt is the charge's expiration date and time (the end of the payment window), with the same value on GET /cash-in/{id}, GET /cash-in and CASHIN_EXPIRED. In v2.1 the value could differ between channels. The envelope eventAt is the send time, not the expiration.
  • Cash-In webhook data follows the GET rules, amount included: the data of every Cash-In event (except CASHIN_REQUESTED) is the same object GET /cash-in/{id} returns at that moment. The one documented difference is on refunded Cash-Ins — see Event Structure.
  • settlement appears only when a bank is involved. Cash-In: on PAID and REFUNDED, now also in the data of CASHIN_PAID and CASHIN_REFUNDED. Cash-Out: on COMPLETED and REFUNDED, and on CANCELLED when a bank had already been assigned (no money left your account). Never on PROCESSING or PENDING.
  • X-Idempotency-Key is optional (still recommended) on POST /cash-in and POST /cash-out. Without it the request is processed normally, and externalReference still blocks duplicates.
  • 409 DUPLICATED_EXTERNAL_REFERENCE also on POST /cash-in, as on POST /cash-out.

Additions

  • reason on refunded Cash-Outs and Cash-Ins, as a code.
  • settlement in the data of CASHIN_PAID and CASHIN_REFUNDED.
  • A code on every error except the authentication 401s: VALIDATION_ERROR, CASHIN_NOT_FOUND, CASHOUT_NOT_FOUND, REFUND_NOT_ALLOWED, MISSING_E2E, INTERNAL_ERROR and the DigitalSignature codes. See Error Handling.
  • GET /cash-in/{id} and GET /cash-out/{id} accept your externalReference, besides internalCode, transactionId and the payment or refund endToEndId. When a value matches more than one transaction, a fixed precedence decides: internalCode, then transactionId, then payment endToEndId, then refund endToEndId, then externalReference; within the same level, the most recent transaction wins.
  • Idempotent-Replayed: true header when a request with the same X-Idempotency-Key and the same body is replayed within 24 hours.
  • Idempotency error codes: 400 IDEMPOTENCY_KEY_INVALID, 409 IDEMPOTENCY_KEY_IN_PROGRESS, 422 IDEMPOTENCY_KEY_REUSED. See Idempotency.

Checklist for integrators

Search your code for each item and apply the action.

Search forWhereAction
PAIDCash-Out status handlingReplace with COMPLETED. Keep PAID for Cash-In, where it does not change
FAILEDCash-Out status handlingReplace with CANCELLED. The CASHOUT_FAILED event name stays
ANALYSINGCash-Out status handlingRemove. Treat the stage as PENDING
paidAtCash-OutRead completedAt
failedAtCash-OutRead cancelledAt
canceledAtCash-Out and Cash-InRead cancelledAt (two L)
REJECTED, GENERIC_ERRORfailure.code handlingMap the 18 catalog codes. Treat a code you do not know as PROCESSING_ERROR
Parsing of failure.messageCash-OutKey your logic on failure.code. The message is fixed English text
Parsing of reasonCash-OutRead reason as a code, only on REFUNDED
CPF/CNPJpixKeyType handlingAccept CPF and CNPJ as separate values
"REQUESTED"CASHIN_REQUESTED / CASHOUT_REQUESTED handlersExpect AWAITING_PAYMENT (Cash-In) and PROCESSING (Cash-Out)
totals.paidGET /cash-out/summaryRead totals.completed
totals.failedGET /cash-out/summaryRead totals.cancelled, where failed Cash-Outs are now counted
INSUFFICIENT_FUNDS on the POST /cash-out responseCash-Out creationMove the handling to CASHOUT_FAILED with failure.code: "INSUFFICIENT_FUNDS"
PIX_KEY_NOT_FOUND on the POST /cash-out responseCash-Out creationMove the handling to CASHOUT_FAILED with failure.code: "PIX_KEY_NOT_FOUND"
INVALID_CREDENTIALS, TOKEN_EXPIRED, INVALID_APPLICATION_TOKENAuthentication handlingHandle by status and endpoint: a 401 with a WWW-Authenticate header means a new JWT is needed. See Authentication Errors
INVALID_SIGNATUREDigitalSignature handlingHandle 401 DIGITAL_SIGNATURE_REQUIRED, 401 DIGITAL_SIGNATURE_INVALID and 403 CRYPTO_TOKEN_NOT_CONFIGURED
NOT_FOUND, CASH_IN_*, MISSING_END_TO_END_IDError handlingUse CASHIN_NOT_FOUND, CASHOUT_NOT_FOUND, REFUND_NOT_ALLOWED and MISSING_E2E
externalReference generationCash-In and Cash-Out creationKeep it at 50 characters or fewer

Side-by-side example

The same cancelled Cash-Out, delivered as CASHOUT_FAILED. All data is fictitious.

v2.1

{
  "eventType": "CASHOUT_FAILED",
  "eventAt": "2026-03-10T14:00:20Z",
  "data": {
    "transactionId": "3f9a1c52-7b64-4d0e-9a1b-2c8e5f7d4a10",
    "internalCode": "QWERT12345",
    "externalReference": "withdraw_example_001",
    "status": "FAILED",
    "amount": 500.00,
    "failure": {
      "code": "REJECTED",
      "message": "Transferência rejeitada pela instituição recebedora."
    },
    "payee": {
      "name": "Maria Silva",
      "document": "12345678909",
      "destination": {
        "type": "PIX",
        "pixKeyType": "CPF/CNPJ",
        "pixKey": "12345678909"
      }
    },
    "requestedAt": "2026-03-10T14:00:00-03:00",
    "failedAt": "2026-03-10T14:00:15-03:00"
  }
}

v2.2

{
  "eventType": "CASHOUT_FAILED",
  "eventAt": "2026-03-10T14:00:20Z",
  "data": {
    "transactionId": "3f9a1c52-7b64-4d0e-9a1b-2c8e5f7d4a10",
    "internalCode": "QWERT12345",
    "externalReference": "withdraw_example_001",
    "status": "CANCELLED",
    "amount": 500.00,
    "failure": {
      "code": "PAYEE_BANK_REJECTED",
      "message": "The receiving institution rejected the transfer."
    },
    "payee": {
      "name": "Maria Silva",
      "document": "12345678909",
      "destination": {
        "type": "PIX",
        "pixKeyType": "CPF",
        "pixKey": "12345678909"
      }
    },
    "settlement": {
      "ispb": "87654321",
      "bank": "SETTLEMENT PARTNER B",
      "branch": "0001",
      "account": "654987"
    },
    "requestedAt": "2026-03-10T14:00:00-03:00",
    "cancelledAt": "2026-03-10T14:00:15-03:00"
  }
}

What changed: status FAILED → CANCELLED; failure.code REJECTED → PAYEE_BANK_REJECTED, with its fixed English message; pixKeyType CPF/CNPJ → CPF; failedAt → cancelledAt; and settlement is present because a bank had already been assigned. No money left the account in either version.