Skip to main content

Best Practices

Follow these best practices to ensure smooth integration with the FinHub API.

Registration Best Practices

✅ DO

PracticeDescription
Call categorization hierarchy firstAlways retrieve available categories before registration
Build parametrization correctlyMatch feature requirements exactly
Use strong passwordsMin 12 chars, mixed case, numbers, symbols
Store IDs securelySave customer ID and user ID for future calls
Validate email formatCheck email format before submission
Handle duplicatesCheck for existing customers before creating new ones

❌ DON’T

Anti-PatternIssue
Hardcode category IDsIDs may vary across environments
Skip categorization validationLeads to registration failures
Use weak passwordsWill be rejected by validation
Expose credentials in logsSecurity risk
Submit duplicate emailsWill cause conflicts
Ignore error responsesMiss important validation feedback

Session Management Best Practices

Token Handling

// Good: Store token securely and check expiry
const tokenData = {
  token: response.data.token,
  expiresAt: Date.now() + (response.data.expiresIn * 1000),
  refreshToken: response.data.refreshToken
};

function isTokenValid() {
  return Date.now() < tokenData.expiresAt - 60000; // 1 min buffer
}

async function getValidToken() {
  if (!isTokenValid()) {
    await refreshToken();
  }
  return tokenData.token;
}

Session Security

  • Never store tokens in localStorage for sensitive applications
  • Use httpOnly cookies when possible
  • Implement token refresh before expiry
  • Clear tokens on logout from all storage

Verification Best Practices

✅ DO

PracticeDescription
Submit high-quality imagesClear, well-lit document photos
Check document expiryEnsure documents are not expired
Provide all required documentsCheck requiredDocuments array
Keep customer informedShow verification status updates
Monitor progressPoll status endpoint periodically
Handle rejection gracefullyAllow document resubmission

❌ DON’T

Anti-PatternIssue
Submit blurry imagesWill be rejected
Use expired documentsVerification will fail
Skip required document typesIncomplete verification
Assume immediate approvalHigh-risk may take 1-3 days
Retry failed verification endlesslyWait for guidance

Document Quality Guidelines

RequirementStandard
ResolutionMin 300 DPI
FormatJPEG, PNG, or PDF
SizeMax 5 MB per document
ClarityAll text must be readable
CompletenessAll corners visible

✅ DO

PracticeDescription
Accept all three consentsTerms, Privacy, Data Processing
Record acceptance metadataIP, timestamp, user agent
Store consent versionsTrack which version was accepted
Handle consent expiryRe-prompt when consents expire
async function acceptAllConsents(customerId) {
  const consents = ['terms', 'privacy', 'data-processing'];
  const results = [];
  
  for (const type of consents) {
    const result = await acceptConsent(customerId, type, {
      accepted: true,
      version: '1.0',
      acceptanceTimestamp: new Date().toISOString()
    });
    results.push(result);
  }
  
  return results;
}

Activation Best Practices

Pre-Activation Checklist

async function canActivate(customerId, tenantId) {
  const checks = {
    verification: await checkVerificationStatus(customerId),
    termsConsent: await checkConsent(customerId, 'TERMS_AND_CONDITIONS'),
    privacyConsent: await checkConsent(customerId, 'PRIVACY_POLICY'),
    dataConsent: await checkConsent(customerId, 'DATA_PROCESSING')
  };
  
  const allPassed = 
    checks.verification === 'APPROVED' &&
    checks.termsConsent === 'ACCEPTED' &&
    checks.privacyConsent === 'ACCEPTED' &&
    checks.dataConsent === 'ACCEPTED';
  
  return {
    canActivate: allPassed,
    checks: checks,
    missing: Object.entries(checks)
      .filter(([_, v]) => v !== 'APPROVED' && v !== 'ACCEPTED')
      .map(([k, _]) => k)
  };
}

✅ DO

PracticeDescription
Verify all prerequisitesCheck before attempting activation
Handle activation errorsParse error response for missing items
Inform customer of successSend confirmation notification
Store wallet detailsSave IBAN and wallet ID

❌ DON’T

Anti-PatternIssue
Attempt activation without verificationWill fail with 422
Skip consent acceptanceWill fail with 400
Retry activation repeatedlyDon’t retry without fixing issues
Expose sensitive data in errorsLog internally only

Transaction Best Practices

Order Lifecycle

✅ DO

PracticeDescription
Pre-register beneficiariesAdd beneficiaries before transfers
Use prepare/execute patternAlways prepare before executing
Check limits before transferVerify against daily/monthly limits
Implement idempotencyUse unique references per transaction
Monitor order statusTrack until COMPLETED or FAILED

❌ DON’T

Anti-PatternIssue
Execute without prepareMissing fee calculation
Ignore order expiryPrepared orders expire after 2-3 hours
Retry failed orders blindlyMay cause duplicate transactions
Skip beneficiary validationPEP/sanctions check required

API Integration Patterns

Retry Strategy

async function apiCallWithRetry(fn, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await fn();
    } catch (error) {
      if (error.status === 429) {
        // Rate limited - exponential backoff
        await sleep(Math.pow(2, i) * 1000);
        continue;
      }
      if (error.status >= 500) {
        // Server error - retry with backoff
        await sleep(Math.pow(2, i) * 1000);
        continue;
      }
      // Client error (4xx) - don't retry
      throw error;
    }
  }
  throw new Error('Max retries exceeded');
}

Idempotency

// Generate unique reference for each transaction
function generateReference(prefix, customerId) {
  const timestamp = Date.now();
  const random = Math.random().toString(36).substring(2, 8);
  return `${prefix}-${customerId.slice(-8)}-${timestamp}-${random}`;
}

// Example: TXN-550e8400-1705315200000-a1b2c3

Security Best Practices

AreaRecommendation
API KeysStore in environment variables, never in code
TokensUse short-lived access tokens with refresh
PasswordsNever log or store in plain text
PII DataEncrypt at rest and in transit
Error MessagesDon’t expose internal details to users
Audit LoggingLog all API calls with sanitized data

Performance Best Practices

AreaRecommendation
Batch OperationsUse bulk endpoints where available
CachingCache categorization hierarchy
PaginationUse pagination for list endpoints
Async ProcessingDon’t block on long operations
Connection PoolingReuse HTTP connections