Skip to main content
POST
/
v1
/
card
/
set-pin
/
token
{
  "token": "100a99cf-f4d3-4fa1-9be9-2e9828b20ebb",
  "hostedPageUrl": "https://cards.baanx.com/pin-direct/set?token=100a99cf-f4d3-4fa1-9be9-2e9828b20ebb"
}

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 ComplianceThis 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

Headers

x-client-key
string
required
Your public API client key
x-us-env
boolean
default:false
Set to true to route requests to the US backend environment
Authorization
string
required
Bearer token for authentication

Body

redirectUrl
string
URL to redirect to after the user completes or cancels PIN setupOnly used when isEmbedded=falseExample: https://yourapp.com/dashboard
isEmbedded
boolean
default:false
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
customCss
object
Customize the visual appearance of the hosted PIN setup page

Request Example

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

token
string
Secure, time-limited token (UUID format)Lifetime: ~10 minutesUsage: Single-use token that becomes invalid after access
hostedPageUrl
string
Full URL to the hosted PIN setup pageUsage: 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

{
  "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

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:
  1. User redirected to hosted page
  2. Enters new PIN twice for confirmation
  3. Submits PIN
  4. Redirected to redirectUrl on success

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.');
    }
  }
}
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 ComplianceUsing 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 CommunicationAll 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