# PaymentSheetResponse

The object passed to the `onSuccess` callback after the buyer successfully submits the PaymentSheet. Wraps the [TokenizedResponse](#tokenizedresponse) returned by the tokenization call and, when 3D Secure is enabled, the resulting [ThreeDSResponse](#threedsresponse).

Use `response.tokenizedResponse.id` to create a Payment Instrument via the Finix API. Forward `response.threeDSResponse?.sessionId` to your backend alongside the token when it is non-null.

Token Expiration
Tokens expire **30 minutes** after creation. Pass `response.tokenizedResponse.id` to your backend and create a Payment Instrument immediately.


```kotlin
data class PaymentSheetResponse(
    val tokenizedResponse: TokenizedResponse,
    val threeDSResponse: ThreeDSResponse?,
)
```

| Field | Description |
|  --- | --- |
| `tokenizedResponse` | The [TokenizedResponse](#tokenizedresponse) returned by `/applications/{appId}/tokens`. Always present on success. |
| `threeDSResponse` | Populated when [ThreeDSConfiguration](/android/online/configuration#threedsconfiguration) is set on the sheet's `PaymentSheetConfiguration` and 3DS authentication succeeds. `null` for sheets that don't run 3DS. See [ThreeDSResponse](#threedsresponse). |


## TokenizedResponse

Nested inside `PaymentSheetResponse.tokenizedResponse` on the current API, and returned directly by the [deprecated `onTokenized` callback](/android/online/payment-sheet#deprecated-signature).


```kotlin
data class TokenizedResponse(
    val id: String?,
    val fingerprint: String?,
    val createdAt: String?,
    val updatedAt: String?,
    val type: String?,
    val expiresAt: String?,
    val currency: String?,
)
```

| Field | Description |
|  --- | --- |
| `id` | Token ID — pass this to the Finix API to create a Payment Instrument. |
| `fingerprint` | Unique fingerprint for the underlying payment instrument. |
| `type` | `"PAYMENT_CARD"` or `"BANK_ACCOUNT"`. |
| `expiresAt` | Timestamp when the token expires (30 minutes after creation). |
| `currency` | `"USD"` for most tokens. |
| `createdAt` | Timestamp when the token was created. |
| `updatedAt` | Timestamp of the last update. |


Pass `response.tokenizedResponse.id` to your backend, then call the Finix API to create a Payment Instrument. Once created, use the Payment Instrument ID for all subsequent Finix API calls.

Use `tokenizedResponse.type` to handle card and bank account tokens differently if your integration accepts both.

## ThreeDSResponse

Attached to `PaymentSheetResponse.threeDSResponse` after a successful 3D Secure authentication. Pass `sessionId` to your backend alongside the token ID so the backend can reference the authenticated session when creating the Payment Instrument or Authorization.

ThreeDSResponse fields are stale
`sessionId` is the only field guaranteed to be fresh. All other fields on `ThreeDSResponse` are populated from the initial session-creation response (before the buyer completed authentication) — `state` will typically be `PENDING`, and `authenticationType`, `cardholderAuthentication`, `electronicCommerceIndicator`, and related fields may be missing. If you need the up-to-date authentication result, call [GET /3d_secure_sessions/{id}](https://docs.finix.com/api/3d-secure-sessions/get3dsecuresession) from your backend using `sessionId`.


```kotlin
data class ThreeDSResponse(
    val sessionId: String,
    val sourceId: String,
    val state: ThreeDSState?,
    val authenticationType: ThreeDSAuthenticationType?,
    val cardholderAuthentication: String?,
    val electronicCommerceIndicator: ThreeDSElectronicCommerceIndicator?,
    val transactionId: String?,
    val version: String?,
    val failureCode: ThreeDSFailureCode?,
    val failureMessage: String?,
)
```

| Field | Description |
|  --- | --- |
| `sessionId` | The 3D Secure session ID (e.g. `3d_secure_session_xxx`). Forward this to your backend alongside the token. |
| `sourceId` | Payment instrument source ID the session was created against. |
| `state` | Stale — typically `PENDING` because the value is captured before the buyer completes authentication. Don't branch on this; if `onSuccess` fires with a non-null `sessionId`, the session is authenticated. Issuer-reported authentication failures reach `onFailure` as [`FinixErrorCode.ThreeDSFailed`](/android/online/errors#threedsfailurecode). |
| `authenticationType` | How authentication completed (`ThreeDSAuthenticationType`): `FRICTIONLESS`, `CHALLENGE`, or `ATTEMPT`. May be missing — fetch via GET on the session for the authoritative value. |
| `cardholderAuthentication` | The CAVV (Cardholder Authentication Verification Value) issued by the card network, when provided. |
| `electronicCommerceIndicator` | The ECI value issued by the card network, when provided. |
| `transactionId` | 3DS transaction ID (dsTransID) issued by the directory server. |
| `version` | 3DS protocol version negotiated with the issuer (e.g. `"2.2.0"`). |
| `failureCode` | Populated when `state == FAILED` — a `ThreeDSFailureCode` describing why. `null` on success. |
| `failureMessage` | Human-readable failure explanation, when provided. `null` on success. |


Inspect `threeDSResponse` from inside `onSuccess`. When it's non-null, authentication succeeded — forward `sessionId` to your backend. When `threeDSConfiguration` wasn't set, `threeDSResponse` is `null` — proceed without a session ID. All 3DS failures (issuer authentication, session/challenge errors, timeouts) are delivered via `onFailure` — see [Error Reference](/android/online/errors#3d-secure-error-codes). Don't branch on `threeDSResponse.state`; it reflects the pre-authentication session and is typically `PENDING`.


```kotlin
onSuccess = { response ->
    val tokenId = response.tokenizedResponse.id
    val threeDS = response.threeDSResponse
    if (threeDS != null) {
        createPayment(tokenId = tokenId, threeDSSessionId = threeDS.sessionId)
    } else {
        createPayment(tokenId = tokenId, threeDSSessionId = null)
    }
}
```