# Tokenize credentials
You can use [Flow](https://www.checkout.com/docs/payments/accept-payments/accept-a-payment-on-your-website.md) and [Flow for mobile](https://www.checkout.com/docs/payments/accept-payments/accept-a-payment-on-your-mobile-app.md) to securely collect and tokenize card details without going through the complete payment flow.
You receive a single-use token that you can use to:
- Forward to a third-party payment service provider (PSP).
- Request 3D Secure (3DS) authentication in a standalone session.
---
## Before you start
Make sure you have a Checkout.com [test account](https://www.checkout.com/get-test-account).
Create a [public key and a secret key](https://www.checkout.com/docs/resources/api-authentication/api-keys.md) in the [Dashboard](https://dashboard.checkout.com), with the following key scopes:
- Public key – `payment-sessions:pay` and `vault-tokenization`
- Secret key – `payment-sessions`
---
## How it works
1. Create a Payment Session.
2. Initialize and mount Flow.
3. Tokenize the card details.
---
## Create a Payment Session `Server side`
**Web**
Send a server-side request to securely create a `PaymentSession` object. The `PaymentSession` contains the information required to handle the card tokenization.
Call the [Request a Payment Session](https://api-reference.checkout.com/tag/Flow/#operation/CreatePaymentSession) endpoint with your secret key:
> **Information**
>
> Your base URL's `{prefix}` value is unique to your account and environment. To learn how to retrieve your base URLs for the sandbox and production environments, see [API endpoints](https://www.checkout.com/docs/developer-resources/api/api-endpoints.md).
**Production**
`POST` `https://{prefix}.api.checkout.com/payment-sessions`
**Sandbox**
`POST` `https://{prefix}.api.sandbox.checkout.com/payment-sessions`
### Request example
```json
{
"amount": 1000,
"currency": "GBP",
"reference": "ORD-123A",
"display_name": "Online shop",
"billing": {
"address": {
"country": "GB"
}
},
"customer": {
"name": "Jia Tsang",
"email": "jia.tsang@example.com"
},
"success_url": "https://example.com/payments/success",
"failure_url": "https://example.com/payments/failure"
}
```
### Response example
```json
{
"id": "ps_2Un6I6lRpIAiIEwQIyxWVnV9CqQ",
"payment_session_secret": "pss_9823241e-2cec-4c98-b23d-7b29ow4e2e34",
"payment_session_token": "YmFzZTY0:eyJpZCI6InBzXzJVbjZJNmxScElBaUlFd1FJeXhXVm5WOUNxUSIsImFtb3VudCI6MTAwMCwibG9jYWxlIjoiZW4tR0IiLCJjdXJyZW5jeSI6IkdCUCIsInBheW1lbnRfbWV0aG9kcyI6W3sidHlwZSI6ImNhcmQiLCJjYXJkX3NjaGVtZXMiOlsiVmlzYSIsIk1hc3RlcmNhcmQiLCJBbWV4Il19XSwicmlzayI6eyJlbmFibGVkIjp0cnVlfSwiX2xpbmtzIjp7InNlbGYiOnsiaHJlZiI6Imh0dHBzOi8vYXBpLnNhbmRib3guY2hlY2tvdXQuY29tL3BheW1lbnQtc2Vzc2lvbnMvcHNfMlVuNkk2bFJwSUFpSUV3UUl5eFdWblY5Q3FRIn19fQ==",
"_links": {
"self": {
"href": "https://{prefix}.api.sandbox.checkout.com/payment-sessions/ps_2Un6I6lRpIAiIEwQIyxWVnV9CqQ"
}
}
}
```
**Android**
Send a server-side request to securely create a `PaymentSession` object. The `PaymentSession` contains the information required to handle the card tokenization.
```javascript
const createPaymentSession = async (req, res) => {
const response = await fetch("https://{prefix}.api.checkout.com/payment-sessions", {
method: "POST",
headers: {
Authorization: `Bearer ${secretKey}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
amount: 1000,
currency: "GBP",
reference: "ORD-123A",
display_name: "Online Shop",
billing: {
address: { country: "GB" },
},
customer: {
name: "Jia Tsang",
email: "jia.tsang@example.com",
},
success_url: "https://example.com/payments/success",
failure_url: "https://example.com/payments/failure",
}),
});
const paymentSession = await response.json();
res.json(paymentSession);
};
```
**iOS**
Send a server-side request to securely create a `PaymentSession` object. The `PaymentSession` contains the information required to handle the card tokenization.
```javascript
const createPaymentSession = async (req, res) => {
const response = await fetch("https://{prefix}.api.checkout.com/payment-sessions", {
method: "POST",
headers: {
Authorization: `Bearer ${secretKey}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
amount: 1000,
currency: "GBP",
reference: "ORD-123A",
display_name: "Online Shop",
billing: {
address: { country: "GB" },
},
customer: {
name: "Jia Tsang",
email: "jia.tsang@example.com",
},
success_url: "https://example.com/payments/success",
failure_url: "https://example.com/payments/failure",
}),
});
const paymentSession = await response.json();
res.json(paymentSession);
};
```
---
## Initialize and mount Flow `Client side`
**Web**
Install the `@checkout.com/checkout-web-components` package via npm:
```bash
npm install @checkout.com/checkout-web-components --save
```
Alternatively, load the package directly using a script:
```html
```
> **Note**
>
> To remain PCI compliant, only ever load the script directly from `https://checkout-web-components.checkout.com`. Do not download or host the script yourself, or include it in a bundle.
Use `CheckoutWebComponents` to create a `card` object:
```javascript
const cardComponent = checkout.create('card', {
showPayButton: false,
});
```
Check that the `card` component is available and mount it:
```javascript
if (await cardComponent.isAvailable()) {
cardComponent.mount('#card-container');
}
```
> **Note**
>
> Embedding Flow within an iframe or onto a Shadow DOM is not supported.
**Android**
Add the Flow dependency to your app:
```kotlin
// app gradle file
implementation("com.checkout:checkout-android-components:")
// project gradle file
repositories {
mavenCentral()
}
```
Configure Flow with your public key and the payment session data returned from the server.
You must also provide the `onTokenized` callback in the configuration to receive tokens from Flow.
```kotlin
val config = CheckoutComponentConfiguration(
context = context,
paymentSession = paymentSessionResponse,
publicKey = PUBLIC_KEY,
environment = Environment.PRODUCTION,
componentCallback = ComponentCallback(
onTokenized = { tokenDetails ->
handleTokenDetails(tokenDetails);
}
)
)
CoroutineScope(Dispatchers.IO).launch {
try {
val checkoutComponents = CheckoutComponentsFactory(config).create()
} catch (checkoutError: CheckoutError) {
handleError(checkoutError)
}
}
```
Create a `card` component to capture the card details:
```kotlin
val cardComponent = checkoutComponents.create(
componentName = PaymentMethodName.Card,
)
```
Alternatively, you can create a `card` component and hide the built-in payment button if you want to control when the tokenization is initiated:
```kotlin
// Create a Card component without the built-in payment button
val cardComponent = checkoutComponents.create(
componentName = PaymentMethodName.Card,
specificOptions = ComponentOption(showPayButton = false)
)
// Alternatively, create a Flow component without the built-in payment button
val flowComponent = checkoutComponents.create(
componentName = ComponentName.Flow,
specificOptions = ComponentOption(showPayButton = false)
)
```
Check that the `card` component is available and mount it:
```kotlin
// Check that Card component is available before mounting
if (cardComponent.isAvailable()) {
// Render in Compose
cardComponent.Render()
// Render in a container View
cardComponent.provide(containerView)
}
```
**iOS**
In Xcode, go to _Project_ > _Package Dependencies_ and add `https://github.com/checkout/checkout-ios-components`.
Configure Flow with your public key and the payment session data returned from the server:
You must also provide the `onTokenized` callback in the configuration to receive tokens from Flow.
```swift
import CheckoutComponentsSDK
let configuration = try await CheckoutComponents.Configuration(
paymentSession: paymentSession,
publicKey: publicKey,
environment: environment,
callbacks: .init(
onSuccess: { paymentMethod, paymentID in
// Handle success
},
onError: { error in
// Handle error
},
onTokenized: { token in
handleToken(token)
}
)
)
// Initialize the Flow for mobile payment component:
try checkoutComponentsSDK.create(.flow())
```
Create a `card` component to capture the card details:
```swift
let componentsSDK = CheckoutComponents(configuration: configuration)
let component = componentsSDK.create(.card())
```
Alternatively, you can create a `card` component and hide the built-in payment button if you want to control when the tokenization is initiated:
```swift
// Create a Card component without the built-in payment button
let cardComponent = componentsSDK.create(.card(showPayButton: false))
// Alternatively, create a Flow component without the built-in payment button
let flowComponent = componentsSDK.create(.flow(options: [
.card(showPayButton: false)
]))
```
Check that the `card` component is available and mount it:
```swift
if component.isAvailable {
component.render()
}
```
---
## Tokenize the card details `Client side`
**Web**
Display a submit button that initiates the card tokenization:
```html
```
Use the `tokenize()` method to initiate card tokenization.
The tokenization response is returned as the `data` object. You can access the generated card token within the `data.token` property.
```javascript
const cardPayButton = document.getElementById('card-pay-button');
cardPayButton.addEventListener('click', async () => {
const { data } = await cardComponent.tokenize();
await utilizeToken(data.token);
});
```
**Android**
If you did not hide the built-in payment button when you created the `card` component, the card details are tokenized when the customer taps the payment button.
If you hid the built-in payment button, call the `tokenize()` method to initiate the card tokenization.
```kotlin
// Initiate tokenization if you created a Card component
cardComponent.tokenize()
// Initiate tokenization if you created a Flow component
flowComponent.tokenize()
```
Use the `onTokenized` event handler you passed in the Flow configuration to handle the card token string.
**iOS**
If you did not hide the built-in payment button when you created the `card` component, the card details are tokenized when the customer taps the payment button.
If you hid the built-in payment button, call the `tokenize()` method to initiate the card tokenization.
```swift
// Initiate tokenization if you created a Card component
cardComponent.tokenize()
// Initiate tokenization if you created a Flow component
flowComponent.tokenize()
```
Use the `onTokenized` event handler you passed in the Flow configuration to handle the card token string.
---
## Get token metadata
You can retrieve the details of an active token without consuming it. The token remains usable after retrieving its' metadata.
Call the [Get token metadata](https://api-reference.checkout.com/tag/Tokens/#operation/getTokenMetadata) endpoint, and provide the token ID as the `{tokenId}` path parameter.
> **Information**
>
> Your base URL's `{prefix}` value is unique to your account and environment. To learn how to retrieve your base URLs for the sandbox and production environments, see [API endpoints](https://www.checkout.com/docs/developer-resources/api/api-endpoints.md).
**Production**
`GET` `https://{prefix}.api.checkout.com/tokens/{tokenId}/metadata`
**Sandbox**
`GET` `https://{prefix}.api.sandbox.checkout.com/tokens/{tokenId}/metadata`
### Response example
```json
{
"token": "tok_4gzeau5o2uqubbk6fudbloo47a",
"type": "card",
"expires_on": "2026-05-14T10:11:12Z",
"expiry_month": 12,
"expiry_year": 2030,
"scheme": "Visa",
"last4": "4242",
"bin": "424242",
"card_type": "CREDIT",
"card_category": "CONSUMER",
"issuer": "Test Bank",
"issuer_country": "US",
"product_id": "A",
"product_type": "Visa Traditional",
"billing_address": {
"city": "Anytown",
"country": "US"
}
}
```
---
## Next steps
**[Forward stored credentials](https://www.checkout.com/docs/payments/store-and-manage-credentials/forward-stored-credentials.md)**
Forward the token to a third-party payment services provider (PSP).
**[Standalone sessions](https://www.checkout.com/docs/payments/authenticate-payments/3d-secure/standalone-sessions.md)**
Use the token to request 3D Secure authentication in a standalone session.