Przejdź do głównej zawartości

API Integration Best Practices

This guide provides best practices for integrating with the Cryptofuse API. Following these guidelines will help you create a secure, reliable, and efficient integration.

Security Best Practices​

API Key Management​

API keys grant access to your Cryptofuse account and should be treated with the same level of security as passwords:

  1. Store securely: Never hardcode API keys in your application or include them in your version control system.

    // ❌ Bad - hardcoded API key
    const apiKey = "cryp_1a2b3c4d5e6f7g8h9i0j";

    // ✅ Good - load from environment variables
    const apiKey = process.env.CRYPTOFUSE_API_KEY;
  2. Use environment variables: Store API keys as environment variables or in a secure key management system.

  3. Rotate regularly: Create a schedule for rotating API keys, especially for production environments.

  4. Use the principle of least privilege: Create API keys with only the permissions they need.

  5. Have separate keys for different environments: Use different API keys for development, staging, and production.

Secure Communication​

  1. Always use HTTPS: All API requests must use HTTPS to encrypt data in transit.

  2. Validate SSL certificates: Ensure your HTTP client validates SSL certificates and rejects invalid ones.

  3. Implement certificate pinning: For mobile applications, consider implementing certificate pinning for additional security.

  4. Filter sensitive data in logs: Ensure API keys, tokens, and other sensitive data are not written to logs.

User Authentication with OAuth 2.0​

When implementing user authentication with OAuth 2.0:

  1. Store tokens securely: Use secure HTTP-only cookies for web applications when storing access tokens.

  2. Implement token refresh: Request new OAuth 2.0 access tokens before they expire (typically after 1 hour) to maintain a seamless user experience.

  3. Implement proper logout: Always call the logout endpoint when a user signs out to invalidate the token on the server side.

  4. Handle expired tokens: Detect expired tokens and request a new access token or redirect to the login page when necessary.

Error Handling​

Implement robust error handling to provide a good user experience and simplify debugging:

  1. Check HTTP status codes: Always check the HTTP status code to determine if a request was successful.

  2. Parse error responses: Error responses include detailed information about what went wrong.

    try {
    const response = await fetch('{{BASE_URL}}/payments', {
    method: 'POST',
    headers: {
    'Content-Type': 'application/json',
    'X-API-Key': apiKey
    },
    body: JSON.stringify(paymentData)
    });

    if (!response.ok) {
    const error = await response.json();
    console.error(`Error creating payment: ${error.error.message}`);
    // Handle specific error cases
    if (error.error.code === 'invalid_address') {
    // Show address validation error to user
    }
    return;
    }

    const data = await response.json();
    // Process successful response
    } catch (err) {
    console.error('Network or parsing error:', err);
    }
  3. Implement retry logic: For transient errors (e.g., rate limiting, temporary service issues), implement exponential backoff with jitter.

    async function fetchWithRetry(url, options, maxRetries = 3) {
    let retries = 0;
    while (retries < maxRetries) {
    try {
    const response = await fetch(url, options);
    if (response.status !== 429) return response; // Only retry rate limiting errors

    // If rate limited, wait and retry
    const retryAfter = response.headers.get('Retry-After') || 1;
    const delay = parseInt(retryAfter, 10) * 1000;
    await new Promise(resolve => setTimeout(resolve, delay));
    retries++;
    } catch (err) {
    if (retries === maxRetries - 1) throw err;
    retries++;
    // Add exponential backoff with jitter
    const delay = Math.min(1000 * 2 ** retries + Math.random() * 1000, 10000);
    await new Promise(resolve => setTimeout(resolve, delay));
    }
    }
    }
  4. Log detailed error information: Include request IDs, timestamps, and request details in your error logs.

  5. Present user-friendly error messages: Translate API error codes into user-friendly messages.

Rate Limiting​

The Cryptofuse API implements rate limiting to ensure fair usage for all users:

  1. Monitor rate limit headers: Check the X-RateLimit-* headers to monitor your usage.

    function checkRateLimits(response) {
    const remaining = response.headers.get('X-RateLimit-Remaining');
    const limit = response.headers.get('X-RateLimit-Limit');
    const reset = response.headers.get('X-RateLimit-Reset');

    if (remaining && parseInt(remaining, 10) < 10) {
    console.warn(`Rate limit warning: ${remaining}/${limit} requests remaining. Resets at ${new Date(reset * 1000).toISOString()}`);
    }
    }
  2. Implement a queueing system: For high-volume applications, implement a request queue to stay within rate limits.

  3. Distribute requests evenly: Avoid sending bursts of requests; distribute them evenly over time.

  4. Handle 429 responses: When you receive a 429 response, respect the Retry-After header.

Webhook Integration​

When implementing webhooks for payment and withdrawal notifications:

  1. Verify webhook signatures: Always verify the signature of incoming webhook requests.

    function verifyWebhookSignature(payload, signature, secret) {
    const crypto = require('crypto');
    const hmac = crypto.createHmac('sha256', secret);
    const digest = hmac.update(payload).digest('hex');
    return crypto.timingSafeEqual(
    Buffer.from(digest, 'hex'),
    Buffer.from(signature, 'hex')
    );
    }
  2. Respond quickly: Your webhook endpoint should respond with a 200 status code as quickly as possible.

  3. Process webhooks asynchronously: Handle time-consuming processing outside the request-response cycle.

  4. Implement idempotency: Process webhooks idempotently to handle potential duplicate deliveries.

  5. Log all webhook requests: Maintain detailed logs of all webhook requests for debugging.

Performance Optimization​

Optimize your integration for performance and reliability:

  1. Use connection pooling: Reuse HTTP connections to reduce latency.

  2. Implement caching: Cache responses where appropriate to reduce API calls.

    const cache = new Map();

    async function fetchWithCache(url, options, ttlSeconds = 60) {
    const cacheKey = `${url}-${JSON.stringify(options.body || {})}`;
    const cached = cache.get(cacheKey);

    if (cached && cached.expiry > Date.now()) {
    return cached.data;
    }

    const response = await fetch(url, options);
    const data = await response.json();

    cache.set(cacheKey, {
    data,
    expiry: Date.now() + (ttlSeconds * 1000)
    });

    return data;
    }
  3. Paginate efficiently: For endpoints that return large datasets, use pagination parameters efficiently.

  4. Batch operations: Where possible, use batch operations instead of making multiple single-item requests.

  5. Use compression: Enable GZIP compression in your HTTP client to reduce payload size.

Working with Cryptocurrencies​

The Cryptofuse system supports multiple cryptocurrencies and tokens, but availability may vary by tenant. Follow these best practices when working with cryptocurrencies:

Check Available Cryptocurrencies​

  1. Always check available cryptocurrencies first: Use the /cryptocurrency/available endpoint to determine which cryptocurrencies and tokens are available for your tenant before creating payments or withdrawals.

    async function getAvailableCryptocurrencies() {
    try {
    const response = await fetch('{{BASE_URL}}/cryptocurrency/available', {
    method: 'GET',
    headers: {
    'Authorization': `Bearer ${accessToken}`,
    'Content-Type': 'application/json'
    }
    });

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

    const availableCryptos = await response.json();
    return availableCryptos;
    } catch (error) {
    console.error('Error fetching available cryptocurrencies:', error);
    throw error;
    }
    }
  2. Validate cryptocurrency availability: Before creating a payment or withdrawal, check if the cryptocurrency is available for your tenant.

    function isCryptocurrencyAvailable(cryptoCode, availableCryptos) {
    return availableCryptos.some(crypto => crypto.code === cryptoCode.toUpperCase());
    }

    // Example usage
    const createPayment = async (paymentData) => {
    const availableCryptos = await getAvailableCryptocurrencies();

    if (!isCryptocurrencyAvailable(paymentData.blockchain, availableCryptos)) {
    const availableCodes = availableCryptos.map(crypto => crypto.code).join(', ');
    throw new Error(`Cryptocurrency ${paymentData.blockchain} is not available. Available options: ${availableCodes}`);
    }

    // Proceed with payment creation
    // ...
    };
  3. Validate transaction parameters: Use the /cryptocurrency/validate endpoint to validate cryptocurrency, token, and amount parameters before creating a transaction.

    async function validateTransaction(cryptoCode, amountUsd, tokenCode = null) {
    try {
    const url = new URL('{{BASE_URL}}/cryptocurrency/validate');
    url.searchParams.append('crypto_code', cryptoCode);
    url.searchParams.append('amount_usd', amountUsd);

    if (tokenCode) {
    url.searchParams.append('token_code', tokenCode);
    }

    const response = await fetch(url, {
    method: 'GET',
    headers: {
    'Authorization': `Bearer ${accessToken}`,
    'Content-Type': 'application/json'
    }
    });

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

    const validationResult = await response.json();
    return validationResult.valid;
    } catch (error) {
    console.error('Error validating transaction parameters:', error);
    throw error;
    }
    }
  4. Handle dynamic changes: Remember that available cryptocurrencies can change based on tenant configuration. Always check availability at runtime rather than hardcoding cryptocurrency options.

  5. Be aware of cryptocurrency-specific requirements: Different blockchains have different address formats, transaction fees, and processing times. Design your application to handle these differences.

Exchange Rate Considerations​

  1. Check for mock data: When using the exchange rate endpoint, check the is_mock_data field in the response to determine if the rates are from a live provider or simulated.

    async function getExchangeRate(fromCurrency, toCurrency, amount) {
    try {
    const url = new URL('{{BASE_URL}}/rate');
    url.searchParams.append('fromCurrency', fromCurrency);
    url.searchParams.append('toCurrency', toCurrency);
    url.searchParams.append('amount', amount);
    url.searchParams.append('full', 'true');

    const response = await fetch(url, {
    method: 'GET',
    headers: {
    'Authorization': `Bearer ${accessToken}`,
    'Content-Type': 'application/json'
    }
    });

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

    const rateData = await response.json();

    if (rateData.is_mock_data) {
    console.warn('Exchange rate data is mocked and may not reflect actual market rates');
    }

    return rateData;
    } catch (error) {
    console.error('Error fetching exchange rate:', error);
    throw error;
    }
    }
  2. Consider rate volatility: Cryptocurrency exchange rates can be volatile. Consider implementing a time buffer for payment processing to account for rate fluctuations.

  3. Use rate caching carefully: When caching exchange rates, use short TTLs to ensure rates remain relatively accurate.

  4. Display mock data warnings: If using mock data in a user interface, clearly indicate to users that rates are simulated and not real-time market rates.

Testing​

Implement a comprehensive testing strategy for your integration:

  1. Use the sandbox environment: Test all functionality in the sandbox environment before moving to production.

  2. Create automated tests: Implement automated tests for critical API interactions.

  3. Test error scenarios: Test how your application handles various error responses.

  4. Test rate limiting: Ensure your application handles rate limiting correctly.

  5. Perform load testing: Validate that your integration can handle expected traffic volumes.

Monitoring and Logging​

Implement robust monitoring and logging for your integration:

  1. Monitor API response times: Track and alert on abnormal API response times.

  2. Log all API requests: Maintain detailed logs of all API requests for debugging.

  3. Set up alerts: Configure alerts for unusual error rates or response patterns.

  4. Track business metrics: Monitor key business metrics related to payments and withdrawals.

  5. Implement distributed tracing: For complex integrations, implement distributed tracing to track requests across services.

Going to Production​

When moving your integration to production:

  1. Gradual rollout: Implement a gradual rollout strategy to detect issues early.

  2. Maintain feature parity: Ensure your production environment matches your testing environment.

  3. Document your integration: Create detailed documentation for your integration.

  4. Create a runbook: Develop a runbook for common issues and how to resolve them.

  5. Have a rollback plan: Prepare a plan for rolling back changes if issues occur.

Support and Troubleshooting​

When you need help with your integration:

  1. Check the documentation: Review the API documentation for guidance.

  2. Include relevant information: When contacting support, include request IDs, timestamps, and detailed error information.

  3. Provide reproduction steps: Describe the exact steps to reproduce the issue.

  4. Share code samples: Provide code samples that demonstrate the issue.

  5. Contact support: If you can't resolve the issue, contact our support team at [email protected].

By following these best practices, you'll create a secure, reliable, and efficient integration with the Cryptofuse API. If you have any questions or need further assistance, our support team is ready to help.