Overview
Generates a time-limited secure token that allows users to set or change their card PIN through a PCI-compliant hosted interface. The hosted page includes built-in validation and confirmation flows to ensure the PIN is set correctly and securely.
PCI Compliance This endpoint maintains PCI compliance by handling PIN creation entirely within secure hosted environments. Your application never handles or stores PIN values.
Authentication
This endpoint requires authentication via Bearer token:
Authorization: Bearer YOUR_ACCESS_TOKEN
Request
Your public API client key
Set to true to route requests to the US backend environment
Bearer token for authentication
Body
URL to redirect to after the user completes or cancels PIN setup Only used when isEmbedded=false Example: https://yourapp.com/dashboard
Controls the completion/dismissal behavior:
false - Redirects to redirectUrl when user completes or cancels
true - Fires a postMessage event with type abort for iframe integration
Customize the visual appearance of the hosted PIN setup page Show customCss properties
customCss.backgroundColor
Main background color Example: #F9FAFB, #E5E7EB
Text color against main background Important: Avoid using the same hex as backgroundColorExample: #000000, #111827
customCss.backgroundColorPrimary
Primary background color for buttons and input areas Example: #000000, #1F2937
customCss.textColorPrimary
Text color for buttons and input areas Important: Avoid using the same hex as backgroundColorPrimaryExample: #FFFFFF, #F3F4F6
customCss.buttonBorderRadius
Button border radius in pixels Example: 4, 8, 12
customCss.pinBorderRadius
PIN input container border radius in pixels Example: 2, 4, 8
Border color for PIN input container Default: Same as backgroundColorPrimaryExample: #3B82F6, #10B981
Request Example
cURL
JavaScript
Python
TypeScript
curl -X POST https://dev.api.baanx.com/v1/card/set-pin/token \
-H "x-client-key: YOUR_CLIENT_KEY" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"redirectUrl": "https://yourapp.com/dashboard",
"isEmbedded": false,
"customCss": {
"backgroundColor": "#EFEFEF",
"textColor": "#000000",
"backgroundColorPrimary": "#000000",
"textColorPrimary": "#FFFFFF",
"buttonBorderRadius": 8,
"pinBorderRadius": 4,
"pinBorderColor": "#FF00FF"
}
}'
Response
Success Response
Secure, time-limited token (UUID format) Lifetime: ~10 minutesUsage: Single-use token that becomes invalid after access
Full URL to the hosted PIN setup page Usage: Redirect users or embed in iframeFormat: <HOST>/pin-direct/set?token={token}
{
"token" : "100a99cf-f4d3-4fa1-9be9-2e9828b20ebb" ,
"hostedPageUrl" : "https://cards.baanx.com/pin-direct/set?token=100a99cf-f4d3-4fa1-9be9-2e9828b20ebb"
}
Error Responses
401 - Unauthorized
403 - Forbidden
404 - Card Not Found
498 - Invalid Client Key
499 - Missing Client Key
500 - Internal Server Error
{
"message" : "Not authenticated"
}
Hosted Page Features
The hosted PIN setup page includes:
PIN Entry Secure input fields for entering 4-digit PIN
Confirmation Two-step entry to prevent typos
Validation Real-time validation of PIN format and strength
Masked Input PIN digits are masked for privacy during entry
Integration Methods
Full Page Redirect
Iframe Embedding
Redirect the user to set their PIN on a dedicated page. const { hostedPageUrl } = await generateSetPinToken ({
redirectUrl: 'https://yourapp.com/success' ,
isEmbedded: false
});
window . location . href = hostedPageUrl ;
User Flow:
User redirected to hosted page
Enters new PIN twice for confirmation
Submits PIN
Redirected to redirectUrl on success
Embed the PIN setup within your application. const { hostedPageUrl } = await generateSetPinToken ({
isEmbedded: true
});
const iframe = document . createElement ( 'iframe' );
iframe . src = hostedPageUrl ;
iframe . style . width = '100%' ;
iframe . style . height = '500px' ;
window . addEventListener ( 'message' , ( event ) => {
if ( event . data . type === 'abort' ) {
iframe . remove ();
}
});
document . getElementById ( 'pin-container' ). appendChild ( iframe );
User Flow:
Iframe loads within your app
User enters and confirms PIN
postMessage event fires on completion or cancellation
Your app handles the event appropriately
Use Case Examples
First-Time PIN Setup
async function setupCardPIN () {
try {
const { hostedPageUrl } = await generateSetPinToken ({
redirectUrl: ` ${ window . location . origin } /card-activated` ,
isEmbedded: false
});
showInfo ( 'You will now set your card PIN' );
window . location . href = hostedPageUrl ;
} catch ( error ) {
console . error ( 'Failed to initiate PIN setup:' , error );
showError ( 'Unable to set PIN. Please try again.' );
}
}
Change Existing PIN
async function changePIN () {
const confirmed = await showConfirmDialog ({
title: 'Change PIN?' ,
message: 'You will be able to set a new 4-digit PIN for your card.' ,
confirmText: 'Change PIN' ,
cancelText: 'Cancel'
});
if ( confirmed ) {
try {
const { hostedPageUrl } = await generateSetPinToken ({
redirectUrl: window . location . href ,
isEmbedded: false
});
window . location . href = hostedPageUrl ;
} catch ( error ) {
console . error ( 'Failed to change PIN:' , error );
showError ( 'Unable to change PIN. Please try again.' );
}
}
}
Modal PIN Setup
function PINSetup () {
const [ showModal , setShowModal ] = useState ( false );
const [ iframeUrl , setIframeUrl ] = useState ( '' );
const handleSetPIN = async () => {
try {
const { hostedPageUrl } = await generateSetPinToken ({
isEmbedded: true ,
customCss: {
backgroundColor: '#F9FAFB' ,
textColor: '#111827' ,
backgroundColorPrimary: '#3B82F6' ,
textColorPrimary: '#FFFFFF' ,
buttonBorderRadius: 8 ,
pinBorderRadius: 4
}
});
setIframeUrl ( hostedPageUrl );
setShowModal ( true );
} catch ( error ) {
console . error ( 'Failed to load PIN setup:' , error );
}
};
useEffect (() => {
const handleMessage = ( event : MessageEvent ) => {
if ( event . data . type === 'abort' ) {
setShowModal ( false );
setIframeUrl ( '' );
}
};
window . addEventListener ( 'message' , handleMessage );
return () => window . removeEventListener ( 'message' , handleMessage );
}, []);
return (
<>
< button onClick = { handleSetPIN } > Set Card PIN </ button >
{ showModal && (
< div className = "modal" >
< iframe
src = { iframeUrl }
title = "Set Card PIN"
style = {{ width : '100%' , height : '500px' , border : 'none' }}
/>
</ div >
)}
</>
);
}
Customization Examples
Modern Dark Theme
{
"customCss" : {
"backgroundColor" : "#1F2937" ,
"textColor" : "#F9FAFB" ,
"backgroundColorPrimary" : "#3B82F6" ,
"textColorPrimary" : "#FFFFFF" ,
"buttonBorderRadius" : 12 ,
"pinBorderRadius" : 8 ,
"pinBorderColor" : "#60A5FA"
}
}
Light Theme
{
"customCss" : {
"backgroundColor" : "#FFFFFF" ,
"textColor" : "#111827" ,
"backgroundColorPrimary" : "#10B981" ,
"textColorPrimary" : "#FFFFFF" ,
"buttonBorderRadius" : 8 ,
"pinBorderRadius" : 4
}
}
Brand Colors
{
"customCss" : {
"backgroundColor" : "#FEF3C7" ,
"textColor" : "#78350F" ,
"backgroundColorPrimary" : "#F59E0B" ,
"textColorPrimary" : "#FFFFFF" ,
"buttonBorderRadius" : 10 ,
"pinBorderRadius" : 6 ,
"pinBorderColor" : "#D97706"
}
}
PIN Requirements
Standard PIN Format
Must be exactly 4 digits
Only numeric characters (0-9)
No letters or special characters
Cannot be all the same digit (e.g., 1111, 2222)
The hosted page enforces these requirements automatically with real-time validation.
Security Best Practices
Token Security
Tokens expire after ~10 minutes
Single-use tokens become invalid after first access
Generate new tokens for each PIN setup attempt
Never store, cache, or log tokens
PCI Compliance Using this endpoint ensures PCI compliance as PIN data is created and stored entirely within secure, PCI-compliant systems. Your application never handles PIN values.
Secure Communication All communication with the hosted page occurs over HTTPS with strong encryption. The PIN is never exposed in logs, analytics, or network traffic accessible to your application.
Common Use Cases
Onboarding Flow
async function cardActivationFlow () {
await orderCard ();
let card = await getCardStatus ();
while ( card . status !== 'ACTIVE' ) {
await delay ( 2000 );
card = await getCardStatus ();
}
showSuccess ( 'Card activated! Now set your PIN.' );
const { hostedPageUrl } = await generateSetPinToken ({
redirectUrl: ` ${ window . location . origin } /dashboard` ,
isEmbedded: false
});
window . location . href = hostedPageUrl ;
}
Security Settings
function SecuritySettings () {
return (
< div >
< h2 > Card Security </ h2 >
< button onClick = { changePIN } > Change PIN </ button >
< button onClick = { viewPIN } > View Current PIN </ button >
< button onClick = { freezeCard } > Freeze Card </ button >
</ div >
);
}
Error Handling
async function safelySetPIN () {
try {
const card = await getCardStatus ();
if ( card . status !== 'ACTIVE' ) {
throw new Error ( 'Card must be active to set PIN' );
}
const { hostedPageUrl } = await generateSetPinToken ({
redirectUrl: window . location . href ,
isEmbedded: false
});
window . location . href = hostedPageUrl ;
} catch ( error ) {
if ( error . response ?. status === 404 ) {
showError ( 'No card found. Please order a card first.' );
} else if ( error . response ?. status === 401 ) {
showError ( 'Session expired. Please log in again.' );
} else {
showError ( 'Failed to set PIN. Please try again.' );
}
}
}
POST /v1/card/pin/token - Generate token to view current PIN
POST /v1/card/details/token - Generate token to view card details
GET /v1/card/status - Check card status before PIN setup
POST /v1/card/order - Order a new card