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

# Generate PIN View Token

> Generate a secure token for viewing the card PIN through an image-based display

## Overview

Generates a time-limited secure token that allows users to view their card PIN as a secure image. The PIN is never transmitted to or stored by your application, ensuring security and compliance.

<Info>
  **PCI Compliance**

  This endpoint maintains PCI compliance by delivering PIN data as a secure image. Your application never handles the actual PIN value.
</Info>

## Authentication

This endpoint requires authentication via Bearer token:

```bash theme={null}
Authorization: Bearer YOUR_ACCESS_TOKEN
```

## Request

### Headers

<ParamField header="x-client-key" type="string" required>
  Your public API client key
</ParamField>

<ParamField header="x-us-env" type="boolean" default={false}>
  Set to `true` to route requests to the US backend environment
</ParamField>

<ParamField header="Authorization" type="string" required>
  Bearer token for authentication
</ParamField>

### Body

<Note>
  The request body is **optional**. If omitted, default styling will be applied to the PIN image.
</Note>

<ParamField body="customCss" type="object">
  Customize the visual appearance of the PIN image

  <Expandable title="customCss properties">
    <ParamField body="customCss.backgroundColor" type="string" default="#EFEFEF">
      Background color of the PIN image

      **Example:** `#F9FAFB`, `#E5E7EB`
    </ParamField>

    <ParamField body="customCss.textColor" type="string" default="#000000">
      Text color for the PIN digits

      **Important:** Avoid using the same hex as `backgroundColor` for readability

      **Example:** `#000000`, `#111827`
    </ParamField>
  </Expandable>
</ParamField>

### Request Example

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://dev.api.baanx.com/v1/card/pin/token \
    -H "x-client-key: YOUR_CLIENT_KEY" \
    -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{
      "customCss": {
        "backgroundColor": "#EFEFEF",
        "textColor": "#000000"
      }
    }'
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch('https://dev.api.baanx.com/v1/card/pin/token', {
    method: 'POST',
    headers: {
      'x-client-key': 'YOUR_CLIENT_KEY',
      'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      customCss: {
        backgroundColor: '#EFEFEF',
        textColor: '#000000'
      }
    })
  });

  const data = await response.json();
  console.log('PIN image URL:', data.imageUrl);
  ```

  ```python Python theme={null}
  import requests

  url = "https://dev.api.baanx.com/v1/card/pin/token"
  headers = {
      "x-client-key": "YOUR_CLIENT_KEY",
      "Authorization": "Bearer YOUR_ACCESS_TOKEN",
      "Content-Type": "application/json"
  }
  payload = {
      "customCss": {
          "backgroundColor": "#EFEFEF",
          "textColor": "#000000"
      }
  }

  response = requests.post(url, headers=headers, json=payload)
  data = response.json()
  print(f"PIN image URL: {data['imageUrl']}")
  ```

  ```typescript TypeScript theme={null}
  interface PinTokenRequest {
    customCss?: {
      backgroundColor?: string;
      textColor?: string;
    };
  }

  interface PinTokenResponse {
    token: string;
    imageUrl: string;
  }

  const generatePinToken = async (
    config?: PinTokenRequest
  ): Promise<PinTokenResponse> => {
    const response = await fetch('https://dev.api.baanx.com/v1/card/pin/token', {
      method: 'POST',
      headers: {
        'x-client-key': 'YOUR_CLIENT_KEY',
        'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
        'Content-Type': 'application/json'
      },
      body: config ? JSON.stringify(config) : undefined
    });

    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }

    return await response.json();
  };
  ```
</CodeGroup>

## Response

### Success Response

<ResponseField name="token" type="string">
  Secure, time-limited token (UUID format)

  **Lifetime:** \~10 minutes

  **Usage:** Single-use token that becomes invalid after the image is accessed
</ResponseField>

<ResponseField name="imageUrl" type="string">
  URL that renders PIN as a secure image

  **Usage:** Display PIN by using this URL as the `src` attribute of an `<img>` tag

  **Format:** `<HOST>/details-image?token={token}`

  **Security:** Treat this URL as highly sensitive. Do not log or store it.
</ResponseField>

<ResponseExample>
  ```json 200 - Success theme={null}
  {
    "token": "100a99cf-f4d3-4fa1-9be9-2e9828b20ebb",
    "imageUrl": "https://cards.baanx.com/details-image?token=100a99cf-f4d3-4fa1-9be9-2e9828b20ebb"
  }
  ```
</ResponseExample>

## Error Responses

<ResponseExample>
  ```json 401 - Unauthorized theme={null}
  {
    "message": "Not authenticated"
  }
  ```

  ```json 403 - Forbidden theme={null}
  {
    "message": "Not authorized"
  }
  ```

  ```json 404 - Card Not Found theme={null}
  {
    "message": "Card not found"
  }
  ```

  ```json 422 - Validation Error theme={null}
  {
    "message": "Validation error",
    "errors": [
      {
        "field": "customCss.backgroundColor",
        "message": "Invalid hex color format"
      }
    ]
  }
  ```

  ```json 498 - Invalid Client Key theme={null}
  {
    "message": "Invalid client key"
  }
  ```

  ```json 499 - Missing Client Key theme={null}
  {
    "message": "Missing client key"
  }
  ```

  ```json 500 - Internal Server Error theme={null}
  {
    "message": "Internal server error"
  }
  ```
</ResponseExample>

## Integration Method

Display PIN as a secure image without interactive elements.

### Basic Implementation

```javascript theme={null}
const { imageUrl } = await generatePinToken({
  customCss: {
    backgroundColor: '#EFEFEF',
    textColor: '#000000'
  }
});

const img = document.createElement('img');
img.src = imageUrl;
img.alt = 'Card PIN';
img.style.maxWidth = '100%';
img.style.borderRadius = '8px';

document.getElementById('pin-image-container').appendChild(img);
```

### React Component Example

```typescript theme={null}
import { useState } from 'react';

export function PinImageViewer() {
  const [imageUrl, setImageUrl] = useState<string | null>(null);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);

  const handleViewPin = async () => {
    setLoading(true);
    setError(null);

    try {
      const response = await fetch('https://dev.api.baanx.com/v1/card/pin/token', {
        method: 'POST',
        headers: {
          'x-client-key': 'YOUR_CLIENT_KEY',
          'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({
          customCss: {
            backgroundColor: '#EFEFEF',
            textColor: '#000000'
          }
        })
      });

      if (!response.ok) {
        throw new Error('Failed to generate PIN token');
      }

      const data = await response.json();
      setImageUrl(data.imageUrl);
    } catch (err) {
      setError(err instanceof Error ? err.message : 'An error occurred');
    } finally {
      setLoading(false);
    }
  };

  return (
    <div>
      <button onClick={handleViewPin} disabled={loading}>
        {loading ? 'Loading...' : 'View PIN'}
      </button>

      {error && <div className="error">{error}</div>}

      {imageUrl && (
        <div className="pin-image-container">
          <img
            src={imageUrl}
            alt="Card PIN"
            style={{ maxWidth: '100%', borderRadius: '8px' }}
          />
          <button onClick={() => setImageUrl(null)}>Close</button>
        </div>
      )}
    </div>
  );
}
```

<Warning>
  **Security Note**

  Image URLs contain sensitive PIN information. Always:

  * Use HTTPS only
  * Never log or store the imageUrl
  * Display in secure contexts only
  * Clear the image from DOM when user is done viewing
</Warning>

## Customization Examples

### Dark Theme

```json theme={null}
{
  "customCss": {
    "backgroundColor": "#1F2937",
    "textColor": "#F9FAFB"
  }
}
```

### Light Theme

```json theme={null}
{
  "customCss": {
    "backgroundColor": "#FFFFFF",
    "textColor": "#111827"
  }
}
```

### Brand Colors

```json theme={null}
{
  "customCss": {
    "backgroundColor": "#F0F9FF",
    "textColor": "#0C4A6E"
  }
}
```

## Security Best Practices

<Warning>
  **Token Security**

  * Tokens expire after \~10 minutes
  * Single-use tokens become invalid after first access
  * Generate new tokens for each PIN view request
  * Never store, cache, or log tokens
</Warning>

<Note>
  **PCI Compliance**

  Using this endpoint ensures PCI compliance as PIN data is delivered as a secure image. Your application never handles the actual PIN value.
</Note>

<Info>
  **URL Handling**

  Treat `imageUrl` as highly sensitive. Use HTTPS only, never log these URLs, and display only in authenticated, secure contexts.
</Info>

## Best Practices

### Error Handling

```typescript theme={null}
async function showPIN() {
  try {
    const { imageUrl } = await generatePinToken({
      customCss: {
        backgroundColor: '#EFEFEF',
        textColor: '#000000'
      }
    });

    const img = document.createElement('img');
    img.src = imageUrl;
    img.alt = 'Card PIN';
    img.style.maxWidth = '100%';
    document.getElementById('pin-container').appendChild(img);

  } catch (error) {
    if (error.response?.status === 404) {
      alert('No card found. Please order a card first.');
    } else if (error.response?.status === 401) {
      alert('Session expired. Please log in again.');
    } else if (error.response?.status === 422) {
      alert('Invalid styling parameters. Please check your customCss values.');
    } else {
      alert('Failed to load PIN. Please try again.');
    }
  }
}
```

### Cleanup After Viewing

```typescript theme={null}
function createPINViewer() {
  let currentImage: HTMLImageElement | null = null;

  async function showPIN() {
    const { imageUrl } = await generatePinToken();

    currentImage = document.createElement('img');
    currentImage.src = imageUrl;
    currentImage.alt = 'Card PIN';
    document.getElementById('pin-container').appendChild(currentImage);
  }

  function hidePIN() {
    if (currentImage) {
      currentImage.remove();
      currentImage = null;
    }
  }

  return { showPIN, hidePIN };
}

const pinViewer = createPINViewer();
```

## Related Endpoints

* `POST /v1/card/set-pin/token` - Generate token to set or change card PIN
* `POST /v1/card/details/token` - Generate token to view card details
* `GET /v1/card/status` - Check card status before viewing PIN
