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

# Best Practices

> Implementation best practices for registration, verification, and activation

# Best Practices

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

## Registration Best Practices

### ✅ DO

| Practice                                | Description                                              |
| --------------------------------------- | -------------------------------------------------------- |
| **Call categorization hierarchy first** | Always retrieve available categories before registration |
| **Build parametrization correctly**     | Match feature requirements exactly                       |
| **Use strong passwords**                | Min 12 chars, mixed case, numbers, symbols               |
| **Store IDs securely**                  | Save customer ID and user ID for future calls            |
| **Validate email format**               | Check email format before submission                     |
| **Handle duplicates**                   | Check for existing customers before creating new ones    |

### ❌ DON'T

| Anti-Pattern                   | Issue                              |
| ------------------------------ | ---------------------------------- |
| Hardcode category IDs          | IDs may vary across environments   |
| Skip categorization validation | Leads to registration failures     |
| Use weak passwords             | Will be rejected by validation     |
| Expose credentials in logs     | Security risk                      |
| Submit duplicate emails        | Will cause conflicts               |
| Ignore error responses         | Miss important validation feedback |

***

## Session Management Best Practices

### Token Handling

```javascript theme={null}
// 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

| Practice                           | Description                       |
| ---------------------------------- | --------------------------------- |
| **Submit high-quality images**     | Clear, well-lit document photos   |
| **Check document expiry**          | Ensure documents are not expired  |
| **Provide all required documents** | Check `requiredDocuments` array   |
| **Keep customer informed**         | Show verification status updates  |
| **Monitor progress**               | Poll status endpoint periodically |
| **Handle rejection gracefully**    | Allow document resubmission       |

### ❌ DON'T

| Anti-Pattern                        | Issue                       |
| ----------------------------------- | --------------------------- |
| Submit blurry images                | Will be rejected            |
| Use expired documents               | Verification will fail      |
| Skip required document types        | Incomplete verification     |
| Assume immediate approval           | High-risk may take 1-3 days |
| Retry failed verification endlessly | Wait for guidance           |

### Document Quality Guidelines

| Requirement      | Standard                  |
| ---------------- | ------------------------- |
| **Resolution**   | Min 300 DPI               |
| **Format**       | JPEG, PNG, or PDF         |
| **Size**         | Max 5 MB per document     |
| **Clarity**      | All text must be readable |
| **Completeness** | All corners visible       |

***

## Consent Management Best Practices

### ✅ DO

| Practice                       | Description                      |
| ------------------------------ | -------------------------------- |
| **Accept all three consents**  | Terms, Privacy, Data Processing  |
| **Record acceptance metadata** | IP, timestamp, user agent        |
| **Store consent versions**     | Track which version was accepted |
| **Handle consent expiry**      | Re-prompt when consents expire   |

### Consent Acceptance Pattern

```javascript theme={null}
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

```javascript theme={null}
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

| Practice                       | Description                            |
| ------------------------------ | -------------------------------------- |
| **Verify all prerequisites**   | Check before attempting activation     |
| **Handle activation errors**   | Parse error response for missing items |
| **Inform customer of success** | Send confirmation notification         |
| **Store wallet details**       | Save IBAN and wallet ID                |

### ❌ DON'T

| Anti-Pattern                            | Issue                             |
| --------------------------------------- | --------------------------------- |
| Attempt activation without verification | Will fail with 422                |
| Skip consent acceptance                 | Will fail with 400                |
| Retry activation repeatedly             | Don't retry without fixing issues |
| Expose sensitive data in errors         | Log internally only               |

***

## Transaction Best Practices

### Order Lifecycle

```mermaid theme={null}
flowchart LR
    A[Prepare] --> B{Valid?}
    B -->|Yes| C[Execute]
    B -->|No| D[Fix Issues]
    C --> E[Monitor]
    E --> F{Complete?}
    F -->|Yes| G[Done]
    F -->|No| E
```

### ✅ DO

| Practice                         | Description                           |
| -------------------------------- | ------------------------------------- |
| **Pre-register beneficiaries**   | Add beneficiaries before transfers    |
| **Use prepare/execute pattern**  | Always prepare before executing       |
| **Check limits before transfer** | Verify against daily/monthly limits   |
| **Implement idempotency**        | Use unique references per transaction |
| **Monitor order status**         | Track until COMPLETED or FAILED       |

### ❌ DON'T

| Anti-Pattern                | Issue                                  |
| --------------------------- | -------------------------------------- |
| Execute without prepare     | Missing fee calculation                |
| Ignore order expiry         | Prepared orders expire after 2-3 hours |
| Retry failed orders blindly | May cause duplicate transactions       |
| Skip beneficiary validation | PEP/sanctions check required           |

***

## API Integration Patterns

### Retry Strategy

```javascript theme={null}
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

```javascript theme={null}
// 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

| Area               | Recommendation                                |
| ------------------ | --------------------------------------------- |
| **API Keys**       | Store in environment variables, never in code |
| **Tokens**         | Use short-lived access tokens with refresh    |
| **Passwords**      | Never log or store in plain text              |
| **PII Data**       | Encrypt at rest and in transit                |
| **Error Messages** | Don't expose internal details to users        |
| **Audit Logging**  | Log all API calls with sanitized data         |

***

## Performance Best Practices

| Area                   | Recommendation                     |
| ---------------------- | ---------------------------------- |
| **Batch Operations**   | Use bulk endpoints where available |
| **Caching**            | Cache categorization hierarchy     |
| **Pagination**         | Use pagination for list endpoints  |
| **Async Processing**   | Don't block on long operations     |
| **Connection Pooling** | Reuse HTTP connections             |
