> ## Documentation Index
> Fetch the complete documentation index at: https://docs.y.uno/llms.txt
> Use this file to discover all available pages before exploring further.

# Objects you receive

> The objects the SDK hands back to your app: Status and OneTimeToken.

The objects the SDK hands back to your app: the final status of a transaction, and the one-time token when you create the payment from your backend.

<Tabs>
  <Tab title="Status" id="status">
    The status object reports how the transaction ended. The SDK delivers it through [`onStatus`](/docs/yuno-sdk/controllers/on-status).

    ## What you receive

    The payload carries three pieces:

    * `status`: passed through exactly as the backend returns it, for the statuses this SDK version knows. On Web those are (payments: `CREATED`, `SUCCEEDED`, `PENDING`, `DECLINED`, `REJECTED`, `CANCELED`, `ERROR`, `EXPIRED`, `REFUNDED`, `VERIFIED`, `READY_TO_PAY`; enrollments: `ENROLLED`, `ENROLL_IN_PROCESS`, `UNENROLLED`, `UNENROLL_IN_PROCESS`, `READY_TO_ENROLL`, `CREATED`, `PENDING`, `DECLINED`, `REJECTED`, `CANCELED`, `ERROR`, `EXPIRED`). On every platform, any other value arrives as `INTERNAL_ERROR` with `message.code` `UNSUPPORTED_STATUS` and `message.reason` set to `unsupported status: <value>`.
    * `substatus`: passed through exactly as the backend returns it. On Web an empty or missing substatus arrives as `null`.
    * `message`: extra context. Its shape depends on the source:

    | Source | `message` shape |
    | - | - |
    | Backend returned an `ERROR` / failed response | `{ "source": "backend", "code": <backend error code>, "reason": <backend reason>, "raw": <raw backend payload> }`. On Web and iOS this shape applies when the backend rejects an SDK call (status `INTERNAL_ERROR`), and `code` is the HTTP status when the body has no `code`. |
    | The payment ended `DECLINED`, `REJECTED`, `EXPIRED`, `CANCELED` or `ERROR` | `{ "source": "backend", "code": <transaction response_code> }`, or `null` when the backend sent no response code. On iOS `reason` also carries the transaction's `response_message`. Enrollment outcomes on Web always carry `null`. |
    | SDK failed (failed to render, internal SDK error, network, unexpected exception) | `{ "source": "sdk", "code": <sdk code>, "reason": <human-readable reason>, "context": <render step / module / call site> }` |
    | User cancellation | `null` (not an error) |

    On Web every other payment status, and every enrollment status, carries `message: null`.

    ## Statuses emitted by the SDK itself

    Two statuses are not relayed from the backend, the SDK emits them locally:

    * `INTERNAL_ERROR`: raised when a backend service call failed, or when something failed inside the SDK (load, view rendering, network, unexpected exception).
    * `USER_CANCEL`: raised when the user closes a form or view without completing the flow.

    On Web, `INTERNAL_ERROR` with `message.code` `FORM_INVALID` is not final. The SDK raises it when you submit a form that is not valid, with [`transaction.submit()`](/docs/yuno-sdk/controllers/show-view#web-submit-from-your-own-button) or with `transaction.start({ paymentMethod })` on the payment methods list. The form stays mounted and the user can correct it.

    On Web the `message.code` values for `source: "sdk"` include:

    * `UNSUPPORTED_STATUS`. The backend returned a status the SDK does not know. `message.reason` is `unsupported status: <value>`.
    * `FORM_INVALID`. The submitted form is not valid. Not final.
    * `ELEMENT_NOT_FOUND`. The element passed to `paymentMethodList.mount()` is not in the DOM, or the form's container was removed while the form was loading. A config `elementSelector` that matches nothing makes `start()` reject with `elementSelector "<selector>" was not found in the document.` instead.
    * `COLLECT_FAILED`. In manual mode (you pass `createPayment`), the Mercado Pago wallet failed to collect the payment data. `message.reason` starts with `MERCADO_PAGO_`.
    * `UNEXPECTED_ERROR`. A failure the SDK does not classify. `message.reason` carries the error message.

    On iOS the `message.code` values for `source: "sdk"` are these. `message.context` names the call site that produced the error.

    | Code | When | `context` |
    | - | - | - |
    | `UNSUPPORTED_STATUS` | The backend returned a status the SDK does not know. `reason` is `unsupported status: <value>`. | `status mapping` |
    | `NETWORK_ERROR` | A request timed out (`reason` is `request timed out`) or failed at the transport level (`reason` is the system description). | The call that failed, for example `Transaction.runPayment`, `Transaction.runEnrollment`, `SdkPayments.defaultCreatePayment` or `MethodsViewImplementation.getPaymentMethods` |
    | `THREEDS_ERROR` | The native 3DS setup or challenge failed. `reason` describes the cause, for example `3DS provider unavailable` or `3DS challenge timed out`. | `BaseThreeDSSetupSDKAction.execute` or `PaymentThreeDSChallengeAction.execute` |
    | `CLICK_TO_PAY_FAILED` | Click to Pay failed, or its passkey settings are incomplete. | `PaymentFlowClickToPay` or `PaymentFlowC2PPasskey` |
    | `LOADER_TIMEOUT` | The SDK loader stayed on screen past its limit. `reason` is `loader timeout after <seconds>s`. | `LoaderViewController.timeout` |
    | `INVALID_BROWSER_URL` | A redirect URL could not be opened in the in-app browser. | `YunoViewRouter.showInAppBrowser` |
    | `WEBSOCKET_ERROR` | The status connection for an asynchronous payment failed. | `Websocket` |
    | `NO_PRESENTATION_ANCHOR` | `start` found no view controller to present from. See [`viewController`](/docs/yuno-sdk/reference/objects-you-pass#viewcontroller-ios-only). | `Transaction.start` |
    | `REVOLUT_PAY_FAILED` | Revolut Pay could not start or failed. See [Revolut Pay](/docs/yuno-sdk/features/native-modules#revolut-pay). | `PaymentFlowBase.executePaymentAction` |
    | `UNEXPECTED_ERROR` | A failure the SDK does not classify. `reason` carries the error description. | The call that failed |

    On Web a cancel during a 3DS challenge, for example closing the challenge or pressing the browser back button, arrives as `status: "PENDING"` with `substatus: "USER_CANCEL"` and `message: null`, because the payment already exists on the backend. Calling `transaction.unmount()` on a started transaction that has not delivered a status also emits `USER_CANCEL`, unless a payment is in flight.

    ### Backend failure or SDK failure? Read `message.source`

    `INTERNAL_ERROR` covers both cases, so the `status` alone does not tell you where the failure came from. A backend rejection (for example, an invalid or expired checkout session) arrives as:

    ```json theme={"theme":{"light":"github-dark","dark":"github-dark-dimmed"}}
    {
      "status": "INTERNAL_ERROR",
      "substatus": null,
      "message": {
        "source": "backend",
        "code": "INVALID_CHECKOUT_SESSION",
        "reason": "checkout session expired or already used",
        "raw": "<raw backend error payload>"
      }
    }
    ```

    An SDK-side failure (network, rendering, unexpected exception) arrives as:

    ```json theme={"theme":{"light":"github-dark","dark":"github-dark-dimmed"}}
    {
      "status": "INTERNAL_ERROR",
      "substatus": null,
      "message": {
        "source": "sdk",
        "code": "NETWORK_ERROR",
        "reason": "request timed out",
        "context": "Transaction.runPayment"
      }
    }
    ```

    On Web, `reason` is the backend's `messages[]`, `message` or `description`. For `INVALID_CHECKOUT_SESSION` the SDK appends a hint that a headless transaction needs a session created with workflow `SDK_SEAMLESS`.

    When `message.source` is `"backend"`, Yuno's API rejected a call: `code` and `raw` carry the backend's own error, so start debugging there (session validity, workflow, credentials). When it's `"sdk"`, the failure originated inside the SDK and `context` names the module or call site that produced it.

    ## Backend status values

    The set of possible `status` and `substatus` values is defined by the backend. See the workflow reference for each flow:

    * [Payment status and response codes](https://docs.y.uno/reference/payments/status-and-response-codes/payment)
    * [Enrollment workflow status](https://docs.y.uno/reference/customer-sessions-enrollment/enrollment-workflow#enrollment-status)
    * [Payout workflow status](https://docs.y.uno/reference/payouts/payout-workflow#payout-status)
  </Tab>

  <Tab title="OneTimeToken" id="one-time-token">
    `OneTimeToken` is what the SDK delivers to your `createPayment` handler when you've taken over payment creation. You POST it to `/v1/payments` from your backend.

    On iOS and Android the token is delivered as a dictionary/map (`[String: Any]` / `Map<String, Any>`) with exactly the fields the backend returns; there is no SDK-side reshaping. One exception on iOS: a Click to Pay payment completed with a passkey delivers only `token`. On Web it is a **typed object** with the same fields (`token`, `vaulted_token`, `vault_on_success`, `type`, `card_data`, `customer`, `bank_transfer`), where `vaulted_token` is `null` when no vault token exists; the value passed to `createPayment` additionally carries `recognitionToken` and `checkout_session`. The container type per platform is shown in [`createPayment`](/docs/yuno-sdk/controllers/create-payment).

    For the structure and meaning of each field, see [One-time use token](https://docs.y.uno/docs/basic-concepts/tokens#one-time-use-token).
  </Tab>
</Tabs>

## Related

* [Objects you pass](/docs/yuno-sdk/reference/objects-you-pass). What your app hands to the SDK.
* [`onStatus`](/docs/yuno-sdk/controllers/on-status). Where `Status` is delivered.
* [Take over the SDK](/docs/yuno-sdk/controllers/create-payment). Where `OneTimeToken` is delivered.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.