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,ApplicationTokenandDigitalSignature. - Webhook event names —
CASHIN_*andCASHOUT_*keep their names, includingCASHIN_REQUESTED,CASHOUT_REQUESTEDandCASHOUT_FAILED. What changes is thedatainside some of them.
In the tables below, Before is what v2.1 returned or documented, and After is the v2.2 contract.
| Field | Before (v2.1) | After (v2.2) |
|---|---|---|
status — paid | PAID (and COMPLETED, documented as a legacy synonym) | COMPLETED |
status — money never left | FAILED | CANCELLED |
status — held on the ConnectPSP side | ANALYSING could appear | PENDING |
status — full list | PROCESSING, PENDING, PAID, FAILED, REFUNDED, CANCELLED, COMPLETED | PROCESSING, PENDING, COMPLETED, CANCELLED, REFUNDED |
| Payment date | paidAt | completedAt |
| Failure date | failedAt | Removed. A cancelled Cash-Out carries cancelledAt |
| Cancellation date | canceledAt (one L) | cancelledAt (two L, like the CANCELLED status) |
failure | On FAILED | Only on CANCELLED |
failure.code | REJECTED or GENERIC_ERROR | One code from a fixed catalog of 18 codes — see the failure.code table |
failure.message | Free text, in Portuguese | Fixed per code, in English |
reason | Free text | A code, only on REFUNDED: PAYEE_REQUESTED, FRAUD, OPERATIONAL_ERROR, REVERSED_BY_INSTITUTION or OTHER |
payee.destination.pixKeyType | "CPF/CNPJ" for a document key | CPF or CNPJ. The full list is CPF, CNPJ, EMAIL, PHONE, EVP |
Insufficient balance on POST /cash-out | 422 with code: "INSUFFICIENT_FUNDS" | 202 Accepted, then CASHOUT_FAILED with failure.code: "INSUFFICIENT_FUNDS". Never a 422 |
externalReference maximum length | 100 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.
| Field | Before (v2.1) | After (v2.2) |
|---|---|---|
| Cancellation date | canceledAt (one L) | cancelledAt (two L). CANCELLED is now documented on GET /cash-in/{id} |
reason | Not returned | A code, only on REFUNDED: FRAUD, DUPLICATED_PAYMENT, CUSTOMER_REQUEST, MERCHANT_ERROR, PAYER_NOT_ALLOWED or OTHER |
externalReference maximum length | 100 characters (documented) | 50 characters |
| Event | Before (v2.1) | After (v2.2) |
|---|---|---|
CASHIN_REQUESTED | data.status: "REQUESTED" | data.status: "AWAITING_PAYMENT", as on POST /cash-in and GET /cash-in/{id} |
CASHOUT_REQUESTED | data.status: "REQUESTED" | data.status: "PROCESSING", as on POST /cash-out and GET /cash-out/{id} |
CASHOUT_COMPLETED | data.status: "COMPLETED", completedAt | No change in these fields — GET /cash-out/{id} now uses them too. Adds settlement |
CASHOUT_FAILED | data.status: "FAILED", failure.code REJECTED / GENERIC_ERROR, failedAt | Same event name. data.status: "CANCELLED", failure from the catalog, cancelledAt |
CASHOUT_REFUNDED | reason as free text | reason as a code. Adds settlement |
CASHIN_REFUNDED | No reason | reason 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}.
| Case | Before (v2.1 documentation) | After (v2.2) |
|---|---|---|
Wrong credentials on POST /auth/token | 401 INVALID_CREDENTIALS | 401 with { "message": "..." }, a plain object with no code |
| JWT expired | 401 TOKEN_EXPIRED | 401 with no body and a WWW-Authenticate header (error_description="The token expired at '...'"). Request a new token |
| JWT missing or invalid | 401 | 401 with no body and a WWW-Authenticate header |
ApplicationToken missing or invalid | 401 INVALID_APPLICATION_TOKEN | 401 Problem Details with no code; tell the cases apart by title |
DigitalSignature missing or wrong | 422 INVALID_SIGNATURE | 401 DIGITAL_SIGNATURE_REQUIRED or 401 DIGITAL_SIGNATURE_INVALID; 403 CRYPTO_TOKEN_NOT_CONFIGURED when your client has no CryptoToken |
Insufficient balance on POST /cash-out | 422 INSUFFICIENT_FUNDS | Not an HTTP error: CASHOUT_FAILED with failure.code: "INSUFFICIENT_FUNDS" |
PIX key not found on POST /cash-out | 422 PIX_KEY_NOT_FOUND | Not an HTTP error: CASHOUT_FAILED with failure.code: "PIX_KEY_NOT_FOUND" |
| Transaction not found | 404 NOT_FOUND | 404 CASHIN_NOT_FOUND or 404 CASHOUT_NOT_FOUND |
| Refund of a Cash-In that cannot be refunded | 422 CASH_IN_NOT_PAID, CASH_IN_ALREADY_REFUNDED, CASH_IN_EXPIRED, CASH_IN_CANCELLED | 422 REFUND_NOT_ALLOWED; detail says which case |
| Refund before the payment E2E is available | 422 MISSING_END_TO_END_ID | 422 MISSING_E2E |
The authentication errors are described in Authentication Errors.
GET /cash-out/summary:
| Bucket | Before (v2.1) | After (v2.2) |
|---|---|---|
| Paid | totals.paid | totals.completed |
| Failed | totals.failed | Removed. Counted under totals.cancelled |
| Full list of keys | processing, pending, paid, failed, refunded, cancelled | processing, pending, completed, cancelled, refunded — the Cash-Out statuses in lowercase |
settlement | Paid transactions | completed 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.
These do not break a correct integration, but you may see different values than before.
expiredAtis the charge's expiration date and time (the end of the payment window), with the same value onGET /cash-in/{id},GET /cash-inandCASHIN_EXPIRED. In v2.1 the value could differ between channels. The envelopeeventAtis the send time, not the expiration.- Cash-In webhook
datafollows theGETrules,amountincluded: thedataof every Cash-In event (exceptCASHIN_REQUESTED) is the same objectGET /cash-in/{id}returns at that moment. The one documented difference is on refunded Cash-Ins — see Event Structure. settlementappears only when a bank is involved. Cash-In: onPAIDandREFUNDED, now also in thedataofCASHIN_PAIDandCASHIN_REFUNDED. Cash-Out: onCOMPLETEDandREFUNDED, and onCANCELLEDwhen a bank had already been assigned (no money left your account). Never onPROCESSINGorPENDING.X-Idempotency-Keyis optional (still recommended) onPOST /cash-inandPOST /cash-out. Without it the request is processed normally, andexternalReferencestill blocks duplicates.409 DUPLICATED_EXTERNAL_REFERENCEalso onPOST /cash-in, as onPOST /cash-out.
reasonon refunded Cash-Outs and Cash-Ins, as a code.settlementin thedataofCASHIN_PAIDandCASHIN_REFUNDED.- A
codeon every error except the authentication401s:VALIDATION_ERROR,CASHIN_NOT_FOUND,CASHOUT_NOT_FOUND,REFUND_NOT_ALLOWED,MISSING_E2E,INTERNAL_ERRORand theDigitalSignaturecodes. See Error Handling. GET /cash-in/{id}andGET /cash-out/{id}accept yourexternalReference, besidesinternalCode,transactionIdand the payment or refundendToEndId. When a value matches more than one transaction, a fixed precedence decides:internalCode, thentransactionId, then paymentendToEndId, then refundendToEndId, thenexternalReference; within the same level, the most recent transaction wins.Idempotent-Replayed: trueheader when a request with the sameX-Idempotency-Keyand 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.
Search your code for each item and apply the action.
| Search for | Where | Action |
|---|---|---|
PAID | Cash-Out status handling | Replace with COMPLETED. Keep PAID for Cash-In, where it does not change |
FAILED | Cash-Out status handling | Replace with CANCELLED. The CASHOUT_FAILED event name stays |
ANALYSING | Cash-Out status handling | Remove. Treat the stage as PENDING |
paidAt | Cash-Out | Read completedAt |
failedAt | Cash-Out | Read cancelledAt |
canceledAt | Cash-Out and Cash-In | Read cancelledAt (two L) |
REJECTED, GENERIC_ERROR | failure.code handling | Map the 18 catalog codes. Treat a code you do not know as PROCESSING_ERROR |
Parsing of failure.message | Cash-Out | Key your logic on failure.code. The message is fixed English text |
Parsing of reason | Cash-Out | Read reason as a code, only on REFUNDED |
CPF/CNPJ | pixKeyType handling | Accept CPF and CNPJ as separate values |
"REQUESTED" | CASHIN_REQUESTED / CASHOUT_REQUESTED handlers | Expect AWAITING_PAYMENT (Cash-In) and PROCESSING (Cash-Out) |
totals.paid | GET /cash-out/summary | Read totals.completed |
totals.failed | GET /cash-out/summary | Read totals.cancelled, where failed Cash-Outs are now counted |
INSUFFICIENT_FUNDS on the POST /cash-out response | Cash-Out creation | Move the handling to CASHOUT_FAILED with failure.code: "INSUFFICIENT_FUNDS" |
PIX_KEY_NOT_FOUND on the POST /cash-out response | Cash-Out creation | Move the handling to CASHOUT_FAILED with failure.code: "PIX_KEY_NOT_FOUND" |
INVALID_CREDENTIALS, TOKEN_EXPIRED, INVALID_APPLICATION_TOKEN | Authentication handling | Handle by status and endpoint: a 401 with a WWW-Authenticate header means a new JWT is needed. See Authentication Errors |
INVALID_SIGNATURE | DigitalSignature handling | Handle 401 DIGITAL_SIGNATURE_REQUIRED, 401 DIGITAL_SIGNATURE_INVALID and 403 CRYPTO_TOKEN_NOT_CONFIGURED |
NOT_FOUND, CASH_IN_*, MISSING_END_TO_END_ID | Error handling | Use CASHIN_NOT_FOUND, CASHOUT_NOT_FOUND, REFUND_NOT_ALLOWED and MISSING_E2E |
externalReference generation | Cash-In and Cash-Out creation | Keep it at 50 characters or fewer |
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.