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

# SDK Response Reference

The Gr4vy native SDKs provide a standardized way to handle the results of vaulting and 3DS authentication operations across iOS and Android.

## Success response

When an operation completes successfully, the SDK returns a status object confirming that the card details have been tokenized and, if requested, the 3DS authentication has been attempted.

### Response object

| Field            | Type    | Description                                                     |
| ---------------- | ------- | --------------------------------------------------------------- |
| `tokenized`      | Boolean | Indicates if the card was successfully vaulted/tokenized.       |
| `authentication` | Object  | (Optional) Contains the results of the 3DS authentication flow. |

## The authentication object

If authenticate: true was passed to the tokenize method, the authentication object contains the following fields:

| Field               | Type    | Description                                                                   |
| ------------------- | ------- | ----------------------------------------------------------------------------- |
| `transactionStatus` | String  | The 3DS status code (for example, "Y" for successful, "N" for failed/denied). |
| `attempted`         | Boolean | Indicates if a 3DS authentication was actually attempted.                     |
| `hasTimedOut`       | Boolean | Indicates if the 3DS flow timed out.                                          |
| `hasCancelled`      | Boolean | Indicates if the user manually dismissed the challenge screen.                |
| `type`              | String  | The type of flow performed (for example, "frictionless" or "challenge").      |

## Implementation examples

<CodeGroup>
  ```swift Swift theme={"system"}
  case .success(let status):
      if let auth = status.authentication, auth.user_cancelled {
          // Handle user cancellation
      } else if status.tokenized {
          // Proceed to create a transaction on your backend
      }
  ```

  ```kotlin Kotlin theme={"system"}
  is Gr4vyResult.Success -> {
      val auth = result.data.authentication
      if (auth?.user_cancelled == true) {
          // Handle user cancellation
      } else if (result.data.tokenized) {
          // Proceed to create a transaction on your backend
      }
  }
  ```
</CodeGroup>

## Error handling

Errors are categorized into two types:

1. SDK Failures (returned via the failure callback)
2. Authentication Failures (status flags within a success response)

### 1. Authentication failures (inside success result)

Sometimes the SDK successfully communicates with the 3DS server, but the authentication itself is not "successful" (for example, the user fails the challenge or cancels).
You should check the `authentication` object even when the SDK returns a success result. If authentication was `attempted` but the user `hasCancelled` you
can retry vaulting, or proceed without 3DS.

### 2. SDK failure types (failure callback)

These errors occur when the SDK cannot complete the request due to configuration, network, or validation issues. Please see
the generic guides on how to handle these errors in [Swift](https://github.com/gr4vy/gr4vy-swift?tab=readme-ov-file#error-handling) and [Kotlin](https://github.com/gr4vy/gr4vy-kotlin?tab=readme-ov-file#error-handling).

<CodeGroup>
  ```swift Swift theme={"system"}
  import gr4vy_swift

  do {
      let paymentOptions = try await gr4vy.paymentOptions.list(request: request)
      // Handle success
  } catch let error as Gr4vyError {
      switch error {
      case .invalidGr4vyId:
          print("Invalid Gr4vy ID provided")
      case .badURL(let url):
          print("Invalid URL: \(url)")
      case .httpError(let statusCode, _, let message):
          print("HTTP \(statusCode): \(message ?? "Unknown error")")
      case .networkError(let urlError):
          print("Network error: \(urlError.localizedDescription)")
      case .decodingError(let message):
          print("Decoding error: \(message)")
      case .threeDSError(let message):
          print("3DS authentication error: \(message)")
      case .uiContextError(let message):
          print("UI context error: \(message)")
      }
  } catch {
      print("Unexpected error: \(error)")
  }
  ```

  ```kotlin Kotlin theme={"system"}
  import com.gr4vy.sdk.*

  lifecycleScope.launch {
      try {
          val paymentOptions = gr4vy.paymentOptions.list(request)
          // Handle success
      } catch (error: Gr4vyError) {
          when (error) {
              is Gr4vyError.InvalidGr4vyId -> {
                  println("Invalid Gr4vy ID provided")
              }
              is Gr4vyError.BadURL -> {
                  println("Invalid URL: ${error.url}")
              }
              is Gr4vyError.HttpError -> {
                  println("HTTP ${error.statusCode}: ${error.errorMessage ?: "Unknown error"}")
                  // Access detailed error information
                  if (error.hasDetails()) {
                      println("Detailed errors: ${error.getDetailedErrorMessage()}")
                  }
              }
              is Gr4vyError.NetworkError -> {
                  println("Network error: ${error.exception.message}")
              }
              is Gr4vyError.DecodingError -> {
                  println("Decoding error: ${error.errorMessage}")
              }
              is Gr4vyError.ThreeDSError -> {
                  println("3D Secure authentication error: ${error.message}")
              }
              is Gr4vyError.UiContextError -> {
                  println("UI context error (Activity required): ${error.message}")
              }
          }
      }
  }
  ```
</CodeGroup>
