> ## 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.

# Profile Management

> Complete guide to viewing and managing user profile information, settings, and verification status

## Overview

Once users are registered and authenticated, they can view and manage their profile information through a set of profile management endpoints. These endpoints provide access to personal details, account settings, and KYC verification status.

<Note>
  All profile management endpoints require authentication. Include the `Authorization: Bearer <token>` header with a valid access token from login.
</Note>

## Quick Reference

<CardGroup cols={2}>
  <Card title="Get User Profile" icon="user">
    Retrieve complete user information including personal details and verification status
  </Card>

  <Card title="Update Settings" icon="gear">
    Modify account preferences and security settings
  </Card>

  <Card title="Verification Status" icon="shield-check">
    Check and initiate identity verification process
  </Card>

  <Card title="Onboarding Details" icon="list-check">
    Retrieve detailed onboarding information by ID
  </Card>
</CardGroup>

## Get User Profile

Retrieve complete profile information for the authenticated user.

### Endpoint

```bash theme={null}
GET /v1/user
```

**API Reference:** [`GET /v1/user`](/api-reference/user/get-user)

### Request

<CodeGroup>
  ```bash cURL theme={null}
  curl -X GET https://dev.api.baanx.com/v1/user \
    -H "x-client-key: YOUR_CLIENT_KEY" \
    -H "Authorization: Bearer YOUR_ACCESS_TOKEN"
  ```

  ```javascript JavaScript/TypeScript theme={null}
  async function getUserProfile(accessToken: string): Promise<UserProfile> {
    const response = await fetch('https://dev.api.baanx.com/v1/user', {
      method: 'GET',
      headers: {
        'x-client-key': 'YOUR_CLIENT_KEY',
        'Authorization': `Bearer ${accessToken}`
      }
    });

    if (!response.ok) {
      throw new Error('Failed to fetch user profile');
    }

    return response.json();
  }

  interface UserProfile {
    id: string;
    email: string;
    firstName: string;
    lastName: string;
    dateOfBirth: string;
    phoneNumber: string;
    phoneCountryCode: string;
    verificationState: 'UNVERIFIED' | 'PENDING' | 'VERIFIED' | 'REJECTED';
    addressLine1: string;
    addressLine2?: string;
    city: string;
    zip: string;
    countryOfResidence: string;
    countryOfNationality: string;
    usState?: string;
    ssn?: string;
  }
  ```

  ```python Python theme={null}
  import requests
  from typing import Dict, Optional

  def get_user_profile(access_token: str) -> Dict:
      response = requests.get(
          'https://dev.api.baanx.com/v1/user',
          headers={
              'x-client-key': 'YOUR_CLIENT_KEY',
              'Authorization': f'Bearer {access_token}'
          }
      )

      response.raise_for_status()
      return response.json()

  profile = get_user_profile('YOUR_ACCESS_TOKEN')
  print(f"User: {profile['firstName']} {profile['lastName']}")
  print(f"Verification: {profile['verificationState']}")
  ```
</CodeGroup>

### Response

```json theme={null}
{
  "id": "100a99cf-f4d3-4fa1-9be9-2e9828b20ebb",
  "firstName": "John",
  "lastName": "Doe",
  "dateOfBirth": "1990-01-01",
  "email": "user@example.com",
  "verificationState": "VERIFIED",
  "phoneNumber": "7400846282",
  "phoneCountryCode": "+44",
  "addressLine1": "23 Werrington Bridge Rd",
  "addressLine2": "Milking Nook",
  "city": "Peterborough",
  "zip": "PE6 7PP",
  "countryOfResidence": "GB",
  "countryOfNationality": "GB",
  "usState": null,
  "ssn": null
}
```

### Response Fields

| Field                  | Type           | Description                                            |
| ---------------------- | -------------- | ------------------------------------------------------ |
| `id`                   | string         | Unique user identifier                                 |
| `email`                | string         | User's email address                                   |
| `firstName`            | string         | User's legal first name                                |
| `lastName`             | string         | User's legal last name                                 |
| `dateOfBirth`          | string         | Date of birth (YYYY-MM-DD format)                      |
| `phoneNumber`          | string         | Phone number without country code                      |
| `phoneCountryCode`     | string         | International dialing code (e.g., "+44", "+1")         |
| `verificationState`    | string         | KYC status: UNVERIFIED, PENDING, VERIFIED, or REJECTED |
| `addressLine1`         | string         | Primary address line                                   |
| `addressLine2`         | string \| null | Secondary address line (optional)                      |
| `city`                 | string         | City or town                                           |
| `zip`                  | string         | Postal/ZIP code                                        |
| `countryOfResidence`   | string         | ISO 3166-1 alpha-2 country code                        |
| `countryOfNationality` | string         | ISO 3166-1 alpha-2 nationality code                    |
| `usState`              | string \| null | US state code (only for US residents)                  |
| `ssn`                  | string \| null | Masked SSN (only for US residents)                     |

<Info>
  Sensitive fields like SSN are masked in the response for security. Full SSN is never returned via API.
</Info>

### Use Cases

**Display User Dashboard:**

```javascript theme={null}
const profile = await getUserProfile(accessToken);

document.getElementById('userName').textContent =
  `${profile.firstName} ${profile.lastName}`;
document.getElementById('userEmail').textContent = profile.email;
document.getElementById('verificationBadge').textContent =
  profile.verificationState;
```

**Check Verification Before Action:**

```javascript theme={null}
const profile = await getUserProfile(accessToken);

if (profile.verificationState !== 'VERIFIED') {
  alert('Please complete identity verification to access this feature');
  redirectToVerification();
}
```

**Prefill Edit Forms:**

```javascript theme={null}
const profile = await getUserProfile(accessToken);

document.getElementById('firstName').value = profile.firstName;
document.getElementById('lastName').value = profile.lastName;
document.getElementById('email').value = profile.email;
```

### Common Errors

<AccordionGroup>
  <Accordion title="Unauthorized (401)">
    ```json theme={null}
    {
      "message": "Unauthorized"
    }
    ```

    **Resolution**: Access token is missing, invalid, or expired. Re-authenticate the user.
  </Accordion>

  <Accordion title="User Not Found (404)">
    ```json theme={null}
    {
      "message": "User not found"
    }
    ```

    **Resolution**: User account may have been deleted or token belongs to different environment.
  </Accordion>
</AccordionGroup>

## Verification Status

Check the user's identity verification status and initiate the verification process if needed.

### Endpoint

```bash theme={null}
GET /v1/user/verification
```

**API Reference:** [`GET /v1/user/verification`](/api-reference/user/verification)

### Request

<CodeGroup>
  ```bash cURL theme={null}
  curl -X GET https://dev.api.baanx.com/v1/user/verification \
    -H "x-client-key: YOUR_CLIENT_KEY" \
    -H "Authorization: Bearer YOUR_ACCESS_TOKEN"
  ```

  ```javascript JavaScript/TypeScript theme={null}
  async function getVerificationSession(
    accessToken: string
  ): Promise<{ sessionUrl: string }> {
    const response = await fetch('https://dev.api.baanx.com/v1/user/verification', {
      method: 'GET',
      headers: {
        'x-client-key': 'YOUR_CLIENT_KEY',
        'Authorization': `Bearer ${accessToken}`
      }
    });

    if (!response.ok) {
      throw new Error('Failed to get verification session');
    }

    return response.json();
  }

  const { sessionUrl } = await getVerificationSession(accessToken);
  window.location.href = sessionUrl;
  ```

  ```python Python theme={null}
  def get_verification_session(access_token: str) -> str:
      response = requests.get(
          'https://dev.api.baanx.com/v1/user/verification',
          headers={
              'x-client-key': 'YOUR_CLIENT_KEY',
              'Authorization': f'Bearer {access_token}'
          }
      )

      response.raise_for_status()
      data = response.json()
      return data['sessionUrl']

  session_url = get_verification_session('YOUR_ACCESS_TOKEN')
  print(f"Complete verification at: {session_url}")
  ```
</CodeGroup>

### Response

```json theme={null}
{
  "sessionUrl": "https://example.com?sessionId=12345-12345-12345b"
}
```

### How It Works

This endpoint generates a time-limited, single-use verification session URL where users complete identity verification:

<Steps>
  <Step title="Request Verification Session">
    Call [`GET /v1/user/verification`](/api-reference/user/verification) to generate a unique session URL
  </Step>

  <Step title="Redirect User">
    Direct the user to the returned `sessionUrl` to complete verification
  </Step>

  <Step title="User Completes Verification">
    User submits identity documents and biometric verification (handled by verification provider)
  </Step>

  <Step title="Check Status">
    User's `verificationState` is updated to PENDING or VERIFIED after completion
  </Step>
</Steps>

<Warning>
  Verification session URLs are time-limited and single-use. Generate a new URL if the session expires or is abandoned.
</Warning>

### Verification States

| State          | Description                          | Next Action                                          |
| -------------- | ------------------------------------ | ---------------------------------------------------- |
| **UNVERIFIED** | User has not started verification    | Call this endpoint to get session URL                |
| **PENDING**    | Verification submitted, under review | Wait for manual review (typically 1-3 business days) |
| **VERIFIED**   | Identity confirmed                   | User has full account access                         |
| **REJECTED**   | Verification failed                  | Contact support or resubmit with correct information |

### Implementation Example

<CodeGroup>
  ```javascript JavaScript/TypeScript theme={null}
  class VerificationManager {
    private apiBase: string;
    private clientKey: string;

    constructor(apiBase: string, clientKey: string) {
      this.apiBase = apiBase;
      this.clientKey = clientKey;
    }

    async checkAndPromptVerification(accessToken: string): Promise<void> {
      const profile = await this.getUserProfile(accessToken);

      switch (profile.verificationState) {
        case 'UNVERIFIED':
          if (confirm('Identity verification required. Start now?')) {
            await this.startVerification(accessToken);
          }
          break;

        case 'PENDING':
          alert('Your verification is under review. This usually takes 1-3 business days.');
          break;

        case 'VERIFIED':
          console.log('User is verified');
          break;

        case 'REJECTED':
          alert('Your verification was rejected. Please contact support or try again.');
          break;
      }
    }

    async startVerification(accessToken: string): Promise<void> {
      try {
        const response = await fetch(`${this.apiBase}/v1/user/verification`, {
          method: 'GET',
          headers: {
            'x-client-key': this.clientKey,
            'Authorization': `Bearer ${accessToken}`
          }
        });

        if (!response.ok) {
          throw new Error('Failed to start verification');
        }

        const { sessionUrl } = await response.json();
        window.location.href = sessionUrl;
      } catch (error) {
        console.error('Verification error:', error);
        throw error;
      }
    }

    private async getUserProfile(accessToken: string): Promise<any> {
      const response = await fetch(`${this.apiBase}/v1/user`, {
        method: 'GET',
        headers: {
          'x-client-key': this.clientKey,
          'Authorization': `Bearer ${accessToken}`
        }
      });

      if (!response.ok) {
        throw new Error('Failed to fetch profile');
      }

      return response.json();
    }
  }

  const verificationManager = new VerificationManager(
    'https://dev.api.baanx.com',
    'YOUR_CLIENT_KEY'
  );

  verificationManager.checkAndPromptVerification('YOUR_ACCESS_TOKEN');
  ```

  ```python Python theme={null}
  from typing import Dict

  class VerificationManager:
      def __init__(self, api_base: str, client_key: str):
          self.api_base = api_base
          self.client_key = client_key

      def check_and_prompt_verification(self, access_token: str) -> None:
          profile = self.get_user_profile(access_token)
          state = profile['verificationState']

          if state == 'UNVERIFIED':
              print('Identity verification required.')
              if input('Start now? (y/n): ').lower() == 'y':
                  self.start_verification(access_token)

          elif state == 'PENDING':
              print('Your verification is under review (1-3 business days).')

          elif state == 'VERIFIED':
              print('User is verified')

          elif state == 'REJECTED':
              print('Verification rejected. Contact support or try again.')

      def start_verification(self, access_token: str) -> str:
          response = requests.get(
              f'{self.api_base}/v1/user/verification',
              headers={
                  'x-client-key': self.client_key,
                  'Authorization': f'Bearer {access_token}'
              }
          )

          response.raise_for_status()
          data = response.json()
          session_url = data['sessionUrl']
          print(f'Complete verification at: {session_url}')
          return session_url

      def get_user_profile(self, access_token: str) -> Dict:
          response = requests.get(
              f'{self.api_base}/v1/user',
              headers={
                  'x-client-key': self.client_key,
                  'Authorization': f'Bearer {access_token}'
              }
          )

          response.raise_for_status()
          return response.json()

  verification_manager = VerificationManager(
      'https://dev.api.baanx.com',
      'YOUR_CLIENT_KEY'
  )

  verification_manager.check_and_prompt_verification('YOUR_ACCESS_TOKEN')
  ```
</CodeGroup>

## Get Onboarding Details

Retrieve detailed onboarding information by onboarding ID. This is useful during the registration process to check progress or resume incomplete registrations.

### Endpoint

```bash theme={null}
GET /v1/auth/register?onboardingId=<ID>
```

**API Reference:** [`GET /v1/auth/register`](/api-reference/auth/register)

### Request

<CodeGroup>
  ```bash cURL theme={null}
  curl -X GET "https://dev.api.baanx.com/v1/auth/register?onboardingId=US_100a99cf-f4d3-4fa1-9be9-2e9828b20ebb" \
    -H "x-client-key: YOUR_CLIENT_KEY" \
    -H "Authorization: Bearer YOUR_ACCESS_TOKEN"
  ```

  ```javascript JavaScript/TypeScript theme={null}
  async function getOnboardingDetails(
    onboardingId: string,
    accessToken: string
  ): Promise<OnboardingDetails> {
    const response = await fetch(
      `https://dev.api.baanx.com/v1/auth/register?onboardingId=${onboardingId}`,
      {
        method: 'GET',
        headers: {
          'x-client-key': 'YOUR_CLIENT_KEY',
          'Authorization': `Bearer ${accessToken}`
        }
      }
    );

    if (!response.ok) {
      throw new Error('Failed to fetch onboarding details');
    }

    return response.json();
  }

  interface OnboardingDetails {
    id: string;
    firstName?: string;
    lastName?: string;
    dateOfBirth?: string;
    email: string;
    verificationState: string;
    addressLine1?: string;
    city?: string;
    zip?: string;
    countryOfResidence: string;
  }
  ```

  ```python Python theme={null}
  def get_onboarding_details(
      onboarding_id: str,
      access_token: str
  ) -> Dict:
      response = requests.get(
          f'https://dev.api.baanx.com/v1/auth/register',
          params={'onboardingId': onboarding_id},
          headers={
              'x-client-key': 'YOUR_CLIENT_KEY',
              'Authorization': f'Bearer {access_token}'
          }
      )

      response.raise_for_status()
      return response.json()

  details = get_onboarding_details(
      'US_100a99cf-f4d3-4fa1-9be9-2e9828b20ebb',
      'YOUR_ACCESS_TOKEN'
  )
  print(f"Registration progress: {details}")
  ```
</CodeGroup>

### Response

```json theme={null}
{
  "id": "100a99cf-f4d3-4fa1-9be9-2e9828b20ebb",
  "firstName": "John",
  "lastName": "Doe",
  "dateOfBirth": "1990-01-01",
  "email": "user@example.com",
  "verificationState": "UNVERIFIED",
  "addressLine1": "23 Werrington Bridge Rd",
  "addressLine2": "Milking Nook",
  "city": "Peterborough",
  "zip": "PE6 7PP",
  "countryOfResidence": "GB",
  "countryOfNationality": "GB",
  "phoneNumber": "7400846282",
  "phoneCountryCode": "+44"
}
```

### Use Cases

**Resume Incomplete Registration:**

```javascript theme={null}
const onboardingData = await getOnboardingDetails(onboardingId, accessToken);

if (!onboardingData.firstName) {
  console.log('Resume from personal details step');
} else if (!onboardingData.addressLine1) {
  console.log('Resume from address step');
} else {
  console.log('Registration appears complete');
}
```

**Validate Registration State:**

```javascript theme={null}
const details = await getOnboardingDetails(onboardingId, accessToken);

if (details.verificationState === 'UNVERIFIED') {
  console.log('Registration complete but verification pending');
  redirectToVerification();
}
```

## Update Account Settings

Modify user account settings and preferences.

<Note>
  This endpoint is referenced in the OpenAPI spec but implementation details may vary based on your environment configuration. Check with your account manager for available settings.
</Note>

### Endpoint

```bash theme={null}
PUT /v1/auth/settings
```

**API Reference:** [`PUT /v1/auth/settings`](/api-reference/auth/settings)

### Common Settings

While specific settings vary by environment, common updateable settings include:

* **Communication Preferences**: Marketing emails, SMS notifications
* **Security Settings**: OTP enable/disable, password changes
* **Privacy Settings**: Data sharing preferences
* **Notification Settings**: Alert preferences

<Warning>
  Settings updates may require re-authentication or email verification depending on the setting type and security requirements.
</Warning>

## Profile Display Component Example

Here's a complete example of a user profile display component:

<CodeGroup>
  ```javascript React Component theme={null}
  import { useState, useEffect } from 'react';

  interface UserProfile {
    id: string;
    email: string;
    firstName: string;
    lastName: string;
    verificationState: 'UNVERIFIED' | 'PENDING' | 'VERIFIED' | 'REJECTED';
    phoneNumber: string;
    phoneCountryCode: string;
    addressLine1: string;
    city: string;
    zip: string;
    countryOfResidence: string;
  }

  function UserProfileCard({ accessToken }: { accessToken: string }) {
    const [profile, setProfile] = useState<UserProfile | null>(null);
    const [loading, setLoading] = useState(true);
    const [error, setError] = useState<string | null>(null);

    useEffect(() => {
      fetchProfile();
    }, []);

    const fetchProfile = async () => {
      try {
        const response = await fetch('https://dev.api.baanx.com/v1/user', {
          headers: {
            'x-client-key': 'YOUR_CLIENT_KEY',
            'Authorization': `Bearer ${accessToken}`
          }
        });

        if (!response.ok) {
          throw new Error('Failed to fetch profile');
        }

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

    const getVerificationBadge = (state: string) => {
      const badges = {
        VERIFIED: { color: 'green', text: 'Verified ✓' },
        PENDING: { color: 'yellow', text: 'Pending Review' },
        UNVERIFIED: { color: 'red', text: 'Not Verified' },
        REJECTED: { color: 'red', text: 'Rejected' }
      };

      const badge = badges[state as keyof typeof badges];
      return (
        <span style={{ color: badge.color, fontWeight: 'bold' }}>
          {badge.text}
        </span>
      );
    };

    if (loading) return <div>Loading profile...</div>;
    if (error) return <div>Error: {error}</div>;
    if (!profile) return <div>No profile data</div>;

    return (
      <div style={{ border: '1px solid #ccc', padding: '20px', borderRadius: '8px' }}>
        <h2>Profile Information</h2>

        <div style={{ marginBottom: '10px' }}>
          <strong>Name:</strong> {profile.firstName} {profile.lastName}
        </div>

        <div style={{ marginBottom: '10px' }}>
          <strong>Email:</strong> {profile.email}
        </div>

        <div style={{ marginBottom: '10px' }}>
          <strong>Phone:</strong> {profile.phoneCountryCode} {profile.phoneNumber}
        </div>

        <div style={{ marginBottom: '10px' }}>
          <strong>Address:</strong> {profile.addressLine1}, {profile.city} {profile.zip}
        </div>

        <div style={{ marginBottom: '10px' }}>
          <strong>Country:</strong> {profile.countryOfResidence}
        </div>

        <div style={{ marginBottom: '10px' }}>
          <strong>Verification Status:</strong>{' '}
          {getVerificationBadge(profile.verificationState)}
        </div>

        {profile.verificationState !== 'VERIFIED' && (
          <button
            onClick={() => window.location.href = '/verification'}
            style={{
              marginTop: '10px',
              padding: '10px 20px',
              backgroundColor: '#007bff',
              color: 'white',
              border: 'none',
              borderRadius: '5px',
              cursor: 'pointer'
            }}
          >
            Complete Verification
          </button>
        )}
      </div>
    );
  }

  export default UserProfileCard;
  ```

  ```python Python Flask theme={null}
  from flask import Flask, render_template, session
  import requests

  app = Flask(__name__)

  @app.route('/profile')
  def profile():
      access_token = session.get('access_token')
      if not access_token:
          return redirect('/login')

      try:
          profile = get_user_profile(access_token)
          return render_template('profile.html', profile=profile)
      except Exception as error:
          return f'Error loading profile: {error}', 500

  def get_user_profile(access_token: str):
      response = requests.get(
          'https://dev.api.baanx.com/v1/user',
          headers={
              'x-client-key': 'YOUR_CLIENT_KEY',
              'Authorization': f'Bearer {access_token}'
          }
      )

      response.raise_for_status()
      return response.json()

  if __name__ == '__main__':
      app.run(debug=True)
  ```
</CodeGroup>

## Best Practices

<CardGroup cols={2}>
  <Card title="Cache Profile Data" icon="database">
    Cache user profile data locally with appropriate TTL to reduce API calls. Refresh when user updates information.
  </Card>

  <Card title="Handle Verification States" icon="shield">
    Provide clear UI/UX for each verification state. Guide users through the verification process.
  </Card>

  <Card title="Secure Token Storage" icon="lock">
    Never expose access tokens in URLs or logs. Use secure storage mechanisms appropriate for your platform.
  </Card>

  <Card title="Error Handling" icon="triangle-exclamation">
    Gracefully handle 401 errors by re-authenticating. Show user-friendly messages for other errors.
  </Card>

  <Card title="Data Validation" icon="check">
    Validate profile data on the client side before display to prevent rendering issues with null/undefined values.
  </Card>

  <Card title="Privacy Considerations" icon="eye-slash">
    Mask sensitive information (SSN, full phone numbers) when displaying to users. Only show full details when necessary.
  </Card>
</CardGroup>

## Security Considerations

### Personal Data Protection

* Never log full user data including SSN, full address, or financial information
* Mask sensitive fields in UI (show last 4 digits of SSN, etc.)
* Implement proper access controls for admin users viewing profiles
* Comply with GDPR, CCPA, and other privacy regulations

### Token Management

* Validate token before each profile request
* Re-authenticate if token is expired or invalid
* Clear local profile cache on logout
* Implement automatic token refresh when approaching expiration

### Verification Status

* Don't bypass verification checks on client side
* Always validate verification status server-side before allowing sensitive operations
* Log verification status changes for audit trails
* Alert users when verification status changes

## Troubleshooting

### Common Issues

<AccordionGroup>
  <Accordion title="Profile Data Not Updating">
    **Symptoms**: Changes made during registration not reflected in profile

    **Causes**:

    * Cached data on client side
    * Token from old session
    * Wrong environment (sandbox vs production)

    **Resolution**:

    * Clear local cache and fetch fresh data
    * Ensure using latest access token
    * Verify `x-client-key` matches registration environment
  </Accordion>

  <Accordion title="Verification Session Expired">
    **Symptoms**: User completes verification but status remains UNVERIFIED

    **Causes**:

    * Session URL expired before completion
    * Network issues during verification
    * Verification failed (documents rejected)

    **Resolution**:

    * Generate new verification session URL
    * Check verification provider dashboard for rejection reasons
    * Wait 1-3 business days for manual review if status is PENDING
  </Accordion>

  <Accordion title="Missing Profile Fields">
    **Symptoms**: Some profile fields are null or undefined

    **Causes**:

    * Incomplete registration
    * Optional fields not provided
    * Different requirements for different countries

    **Resolution**:

    * Check registration completion status
    * Validate all required fields were submitted during registration
    * Handle null values gracefully in UI
  </Accordion>
</AccordionGroup>

### Debug Checklist

When troubleshooting profile issues:

* [ ] Verify access token is valid and not expired
* [ ] Check `x-client-key` matches the user's environment
* [ ] Confirm user completed all registration steps
* [ ] Validate API response status codes and error messages
* [ ] Check network requests in browser DevTools
* [ ] Verify user permissions and verification state
* [ ] Test with different user accounts (verified vs unverified)

## Complete Profile Manager Example

Full-featured profile management class with caching and error handling:

<CodeGroup>
  ```javascript JavaScript/TypeScript theme={null}
  class ProfileManager {
    private apiBase: string;
    private clientKey: string;
    private cache: Map<string, { data: any; timestamp: number }> = new Map();
    private cacheTTL = 5 * 60 * 1000;

    constructor(apiBase: string, clientKey: string) {
      this.apiBase = apiBase;
      this.clientKey = clientKey;
    }

    async getProfile(
      accessToken: string,
      useCache = true
    ): Promise<UserProfile> {
      if (useCache) {
        const cached = this.cache.get('profile');
        if (cached && Date.now() - cached.timestamp < this.cacheTTL) {
          return cached.data;
        }
      }

      try {
        const response = await fetch(`${this.apiBase}/v1/user`, {
          headers: {
            'x-client-key': this.clientKey,
            'Authorization': `Bearer ${accessToken}`
          }
        });

        if (!response.ok) {
          if (response.status === 401) {
            throw new Error('UNAUTHORIZED');
          }
          throw new Error(`HTTP ${response.status}`);
        }

        const data = await response.json();
        this.cache.set('profile', { data, timestamp: Date.now() });
        return data;
      } catch (error) {
        console.error('Failed to fetch profile:', error);
        throw error;
      }
    }

    async startVerification(accessToken: string): Promise<string> {
      try {
        const response = await fetch(`${this.apiBase}/v1/user/verification`, {
          headers: {
            'x-client-key': this.clientKey,
            'Authorization': `Bearer ${accessToken}`
          }
        });

        if (!response.ok) {
          throw new Error('Failed to start verification');
        }

        const { sessionUrl } = await response.json();
        return sessionUrl;
      } catch (error) {
        console.error('Verification error:', error);
        throw error;
      }
    }

    clearCache(): void {
      this.cache.clear();
    }

    isVerified(profile: UserProfile): boolean {
      return profile.verificationState === 'VERIFIED';
    }

    needsVerification(profile: UserProfile): boolean {
      return ['UNVERIFIED', 'REJECTED'].includes(profile.verificationState);
    }

    formatAddress(profile: UserProfile): string {
      const parts = [
        profile.addressLine1,
        profile.addressLine2,
        profile.city,
        profile.zip,
        profile.countryOfResidence
      ].filter(Boolean);

      return parts.join(', ');
    }

    formatPhone(profile: UserProfile): string {
      return `${profile.phoneCountryCode} ${profile.phoneNumber}`;
    }

    maskSsn(ssn?: string): string {
      if (!ssn) return 'Not provided';
      return `***-**-${ssn.slice(-4)}`;
    }
  }

  interface UserProfile {
    id: string;
    email: string;
    firstName: string;
    lastName: string;
    dateOfBirth: string;
    phoneNumber: string;
    phoneCountryCode: string;
    verificationState: 'UNVERIFIED' | 'PENDING' | 'VERIFIED' | 'REJECTED';
    addressLine1: string;
    addressLine2?: string;
    city: string;
    zip: string;
    countryOfResidence: string;
    countryOfNationality: string;
    usState?: string;
    ssn?: string;
  }

  const profileManager = new ProfileManager(
    'https://dev.api.baanx.com',
    'YOUR_CLIENT_KEY'
  );

  async function displayUserDashboard(accessToken: string) {
    try {
      const profile = await profileManager.getProfile(accessToken);

      console.log('User Dashboard');
      console.log('==============');
      console.log(`Name: ${profile.firstName} ${profile.lastName}`);
      console.log(`Email: ${profile.email}`);
      console.log(`Phone: ${profileManager.formatPhone(profile)}`);
      console.log(`Address: ${profileManager.formatAddress(profile)}`);
      console.log(`Verification: ${profile.verificationState}`);

      if (profileManager.needsVerification(profile)) {
        console.log('\n⚠️  Verification required');
        const sessionUrl = await profileManager.startVerification(accessToken);
        console.log(`Complete verification at: ${sessionUrl}`);
      }
    } catch (error) {
      if (error.message === 'UNAUTHORIZED') {
        console.error('Session expired. Please login again.');
      } else {
        console.error('Error:', error);
      }
    }
  }
  ```

  ```python Python theme={null}
  import time
  import requests
  from typing import Dict, Optional

  class ProfileManager:
      CACHE_TTL_SECONDS = 300

      def __init__(self, api_base: str, client_key: str):
          self.api_base = api_base
          self.client_key = client_key
          self.cache = {}

      def get_profile(
          self,
          access_token: str,
          use_cache: bool = True
      ) -> Dict:
          if use_cache and 'profile' in self.cache:
              cached = self.cache['profile']
              if time.time() - cached['timestamp'] < self.CACHE_TTL_SECONDS:
                  return cached['data']

          try:
              response = requests.get(
                  f'{self.api_base}/v1/user',
                  headers={
                      'x-client-key': self.client_key,
                      'Authorization': f'Bearer {access_token}'
                  }
              )

              if response.status_code == 401:
                  raise Exception('UNAUTHORIZED')

              response.raise_for_status()
              data = response.json()

              self.cache['profile'] = {
                  'data': data,
                  'timestamp': time.time()
              }

              return data
          except requests.exceptions.HTTPError as error:
              print(f'Failed to fetch profile: {error}')
              raise

      def start_verification(self, access_token: str) -> str:
          try:
              response = requests.get(
                  f'{self.api_base}/v1/user/verification',
                  headers={
                      'x-client-key': self.client_key,
                      'Authorization': f'Bearer {access_token}'
                  }
              )

              response.raise_for_status()
              data = response.json()
              return data['sessionUrl']
          except requests.exceptions.HTTPError as error:
              print(f'Verification error: {error}')
              raise

      def clear_cache(self) -> None:
          self.cache.clear()

      def is_verified(self, profile: Dict) -> bool:
          return profile['verificationState'] == 'VERIFIED'

      def needs_verification(self, profile: Dict) -> bool:
          return profile['verificationState'] in ['UNVERIFIED', 'REJECTED']

      def format_address(self, profile: Dict) -> str:
          parts = [
              profile.get('addressLine1'),
              profile.get('addressLine2'),
              profile.get('city'),
              profile.get('zip'),
              profile.get('countryOfResidence')
          ]
          return ', '.join([p for p in parts if p])

      def format_phone(self, profile: Dict) -> str:
          return f"{profile['phoneCountryCode']} {profile['phoneNumber']}"

      def mask_ssn(self, ssn: Optional[str]) -> str:
          if not ssn:
              return 'Not provided'
          return f"***-**-{ssn[-4:]}"

  profile_manager = ProfileManager(
      'https://dev.api.baanx.com',
      'YOUR_CLIENT_KEY'
  )

  def display_user_dashboard(access_token: str):
      try:
          profile = profile_manager.get_profile(access_token)

          print('User Dashboard')
          print('==============')
          print(f"Name: {profile['firstName']} {profile['lastName']}")
          print(f"Email: {profile['email']}")
          print(f"Phone: {profile_manager.format_phone(profile)}")
          print(f"Address: {profile_manager.format_address(profile)}")
          print(f"Verification: {profile['verificationState']}")

          if profile_manager.needs_verification(profile):
              print('\n⚠️  Verification required')
              session_url = profile_manager.start_verification(access_token)
              print(f'Complete verification at: {session_url}')
      except Exception as error:
          if str(error) == 'UNAUTHORIZED':
              print('Session expired. Please login again.')
          else:
              print(f'Error: {error}')
  ```
</CodeGroup>

## Next Steps

<CardGroup cols={2}>
  <Card title="Registration Guide" icon="user-plus" href="/guides/user/registration">
    Learn about the complete registration process
  </Card>

  <Card title="Authentication Guide" icon="lock" href="/guides/user/authentication">
    Implement secure login and session management
  </Card>

  <Card title="User Overview" icon="book-open" href="/guides/user/overview">
    Complete user management overview
  </Card>

  <Card title="API Reference" icon="code" href="/api-reference/introduction">
    Full endpoint documentation
  </Card>
</CardGroup>
