Skip to main content

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.
All profile management endpoints require authentication. Include the Authorization: Bearer <token> header with a valid access token from login.

Quick Reference

Get User Profile

Retrieve complete user information including personal details and verification status

Update Settings

Modify account preferences and security settings

Verification Status

Check and initiate identity verification process

Onboarding Details

Retrieve detailed onboarding information by ID

Get User Profile

Retrieve complete profile information for the authenticated user.

Endpoint

GET /v1/user
API Reference: GET /v1/user

Request

curl -X GET https://dev.api.baanx.com/v1/user \
  -H "x-client-key: YOUR_CLIENT_KEY" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN"

Response

{
  "id": "100a99cf-f4d3-4fa1-9be9-2e9828b20ebb",
  "firstName": "John",
  "lastName": "Doe",
  "dateOfBirth": "1990-01-01",
  "email": "[email protected]",
  "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

FieldTypeDescription
idstringUnique user identifier
emailstringUser’s email address
firstNamestringUser’s legal first name
lastNamestringUser’s legal last name
dateOfBirthstringDate of birth (YYYY-MM-DD format)
phoneNumberstringPhone number without country code
phoneCountryCodestringInternational dialing code (e.g., “+44”, “+1”)
verificationStatestringKYC status: UNVERIFIED, PENDING, VERIFIED, or REJECTED
addressLine1stringPrimary address line
addressLine2string | nullSecondary address line (optional)
citystringCity or town
zipstringPostal/ZIP code
countryOfResidencestringISO 3166-1 alpha-2 country code
countryOfNationalitystringISO 3166-1 alpha-2 nationality code
usStatestring | nullUS state code (only for US residents)
ssnstring | nullMasked SSN (only for US residents)
Sensitive fields like SSN are masked in the response for security. Full SSN is never returned via API.

Use Cases

Display User Dashboard:
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:
const profile = await getUserProfile(accessToken);

if (profile.verificationState !== 'VERIFIED') {
  alert('Please complete identity verification to access this feature');
  redirectToVerification();
}
Prefill Edit Forms:
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

{
  "message": "Unauthorized"
}
Resolution: Access token is missing, invalid, or expired. Re-authenticate the user.
{
  "message": "User not found"
}
Resolution: User account may have been deleted or token belongs to different environment.

Verification Status

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

Endpoint

GET /v1/user/verification
API Reference: GET /v1/user/verification

Request

curl -X GET https://dev.api.baanx.com/v1/user/verification \
  -H "x-client-key: YOUR_CLIENT_KEY" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN"

Response

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

Request Verification Session

Call GET /v1/user/verification to generate a unique session URL
2

Redirect User

Direct the user to the returned sessionUrl to complete verification
3

User Completes Verification

User submits identity documents and biometric verification (handled by verification provider)
4

Check Status

User’s verificationState is updated to PENDING or VERIFIED after completion
Verification session URLs are time-limited and single-use. Generate a new URL if the session expires or is abandoned.

Verification States

StateDescriptionNext Action
UNVERIFIEDUser has not started verificationCall this endpoint to get session URL
PENDINGVerification submitted, under reviewWait for manual review (typically 1-3 business days)
VERIFIEDIdentity confirmedUser has full account access
REJECTEDVerification failedContact support or resubmit with correct information

Implementation Example

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');

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

GET /v1/auth/register?onboardingId=<ID>
API Reference: GET /v1/auth/register

Request

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"

Response

{
  "id": "100a99cf-f4d3-4fa1-9be9-2e9828b20ebb",
  "firstName": "John",
  "lastName": "Doe",
  "dateOfBirth": "1990-01-01",
  "email": "[email protected]",
  "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:
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:
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.
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.

Endpoint

PUT /v1/auth/settings
API Reference: PUT /v1/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
Settings updates may require re-authentication or email verification depending on the setting type and security requirements.

Profile Display Component Example

Here’s a complete example of a user profile display component:
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;

Best Practices

Cache Profile Data

Cache user profile data locally with appropriate TTL to reduce API calls. Refresh when user updates information.

Handle Verification States

Provide clear UI/UX for each verification state. Guide users through the verification process.

Secure Token Storage

Never expose access tokens in URLs or logs. Use secure storage mechanisms appropriate for your platform.

Error Handling

Gracefully handle 401 errors by re-authenticating. Show user-friendly messages for other errors.

Data Validation

Validate profile data on the client side before display to prevent rendering issues with null/undefined values.

Privacy Considerations

Mask sensitive information (SSN, full phone numbers) when displaying to users. Only show full details when necessary.

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

Symptoms: Changes made during registration not reflected in profileCauses:
  • 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
Symptoms: User completes verification but status remains UNVERIFIEDCauses:
  • 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
Symptoms: Some profile fields are null or undefinedCauses:
  • 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

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:
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);
    }
  }
}

Next Steps