onStatus is invoked when the transaction reaches its final state. It is the only way to know how the transaction ended.
On iOS, onStatus can run more than once for one transaction. Asynchronous methods (PIX, boleto, OXXO, bank transfers and similar) report status PENDING as soon as the payment exists and the shopper has the payment instructions, with the backend substatus when there is one. The final status arrives in a later call, once Yuno confirms the payment. If the shopper closes the instructions screen, the SDK reports PENDING with substatus CLOSED_BY_USER. Treat PENDING as not final: keep your screen in a waiting state and confirm the outcome on your server.
On Web, these deliveries are not final. The form stays mounted after them, so the shopper can try again:
INTERNAL_ERRORwithmessage.codeFORM_INVALID. You submitted a form that is not valid, withtransaction.submit()or withtransaction.start({ paymentMethod })on the payment methods list.DECLINEDorERRORfor a card payment the SDK can retry, when you overridecreatePayment. The SDK moves the form to a new checkout session, shows the field errors and keeps the form. Enable your pay button again. The nextsubmit()orstart()pays on the new session, whichtoken.checkout_sessioncarries intocreatePayment. WithoutcreatePayment, a form mounted bystart()has no in-place retry: the decline is final and reachesonStatus. On the payment methods list and with secure fields the SDK retries in place and does not callonStatusfor the declined attempt.INTERNAL_ERRORwithmessage.codeCOLLECT_FAILED, when you overridecreatePaymentand a Mercado Pago wallet fails before it produces a token. The wallet button stays mounted.
Behavior
This controller has no default behavior. If you don’t implement it, you won’t receive the final status. On Web,transaction() also prints a console warning when the config has no onStatus function. When implemented, the SDK delivers the final status to your handler after tokenization, payment creation (or merchant-side payment creation via createPayment), 3DS, and status resolution have completed.
Signature
- Web
- iOS
- Android
Wire it as a field on the config.
result carries status, substatus and message. status and substatus are the backend values, with substatus as null when the backend sent none. On a DECLINED, REJECTED, EXPIRED, CANCELED or ERROR payment, message is { source: 'backend', code: <response_code> } when the backend sent a response code, and null otherwise. Every other backend status, on payment and enrollment flows, carries message: null. A status value this SDK version does not know is not passed through. It arrives as INTERNAL_ERROR with message.code UNSUPPORTED_STATUS and message.reason set to unsupported status: <value>. It is the same payload shape on payment and enrollment flows. There is no separate result type per flow.Status for the shape of the payload, the message field, and the SDK-emitted values (INTERNAL_ERROR, USER_CANCEL).
On Web, an INTERNAL_ERROR with message.source 'sdk' can carry values such as these in message.code:
FORM_INVALID. The submitted form is not valid. Not final, see above.COLLECT_FAILED. A wallet failed before it produced a token.message.reasonnames the cause.UNSUPPORTED_STATUS. The backend returned a status this SDK version does not know.message.reasonisunsupported status: <value>.ELEMENT_NOT_FOUND. The element passed topaymentMethodList.mount()is not in the document, or the form’s container was removed while the form was loading. A configelementSelectorthat matches nothing makesstart()reject withelementSelector "<selector>" was not found in the document.instead.UNEXPECTED_ERROR. A failure the SDK does not classify, including an SDK chunk that failed to download.message.reasoncarries the error message.
message.source 'backend', message.code is the backend error code, or the HTTP status when the response body has none. Branch on message.code for the cases you handle and treat the rest as a generic failure.
On Web, USER_CANCEL also arrives when you call transaction.unmount() while a form is mounted and the transaction has not delivered a status yet, unless a payment is in flight. Unmount after onStatus has fired, or treat that delivery as the shopper leaving the payment.
Confirm on your server
onStatus runs on the user’s device, so it can be missed (the app is killed, the network drops, the user closes the page mid-flow) or manipulated (anything running on the client can be tampered with). A SUCCEEDED delivered to your handler is not proof that money moved.
Before shipping goods, granting access, or marking an order as paid, confirm the outcome on your backend:
- Webhooks (recommended). Configure webhooks so Yuno notifies your backend of every payment status change, independently of what happens on the client. Verify the notification signature before trusting it.
- Query the API. Have your backend call Retrieve Payment by ID (or by
merchant_order_id) and read the status from the response.
onStatus as the trigger to update the screen, and the server-side confirmation as the trigger to fulfill.
Threading
On iOS and Android,onStatus is invoked on the main thread. You can update UI directly from inside this handler.
Related
Status. Values and substatus information.- Transactions. How a payment flows through Yuno.
- Payment status values. Status and substatus reference.
showStatusScreen. Flag to enable or disable the SDK’s built-in result screen.