Skip to main content

Troubleshooting

Common issues, solutions, and debugging tips for integrating with the Debitura Customer API. This guide helps you quickly resolve problems and optimize your integration.

Common Issues

Authentication Problems

Issue: "Invalid API credentials"

Symptoms:

  • 401 Unauthorized responses
  • "Invalid API key" error messages
  • Authentication endpoint returns error

Solutions:

  1. Verify credentials:

    // Check your credentials are correct
    console.log('API Key:', process.env.DEBITURA_API_KEY);
    console.log('API Secret length:', process.env.DEBITURA_API_SECRET?.length);
  2. Check credential format:

    • API keys should start with dk_live_ or dk_test_
    • Ensure no leading/trailing whitespace
    • Verify credentials are from the correct environment (test vs production)
  3. Regenerate credentials:

    • Log into Debitura portal
    • Navigate to Settings > API Credentials
    • Generate new credentials if needed
  4. Environment configuration:

    // Ensure environment variables are loaded
    require('dotenv').config();

    if (!process.env.DEBITURA_API_KEY) {
    throw new Error('DEBITURA_API_KEY not configured');
    }

Issue: "Token expired"

Symptoms:

  • 401 responses after initial success
  • "Token has expired" error messages
  • Intermittent authentication failures

Solutions:

  1. Implement token refresh:

    async function ensureValidToken() {
    if (!accessToken || Date.now() >= tokenExpiry) {
    await authenticate();
    }
    }
  2. Add buffer time:

    // Refresh 5 minutes before actual expiry
    const tokenExpiry = Date.now() + ((expiresIn - 300) * 1000);
  3. Handle 401 responses:

    async function request(endpoint) {
    let response = await fetch(endpoint, { headers });

    if (response.status === 401) {
    // Token expired, re-authenticate
    await authenticate();
    response = await fetch(endpoint, { headers });
    }

    return response;
    }

Case Creation Issues

Issue: "Validation error: Invalid debtor information"

Symptoms:

  • 400 Bad Request responses
  • Validation error messages
  • Cases not created

Common causes and solutions:

  1. Invalid CVR number:

    // CVR must be exactly 8 digits
    const cvr = debtorCvr.replace(/\D/g, '').padStart(8, '0');

    if (cvr.length !== 8) {
    throw new Error('CVR must be 8 digits');
    }
  2. Missing required fields:

    // Required fields checklist
    const requiredFields = [
    'debtorName',
    'debtorEmail',
    'principalAmount',
    'currency',
    'invoiceNumber',
    'dueDate'
    ];

    for (const field of requiredFields) {
    if (!caseData[field]) {
    throw new Error(`Missing required field: ${field}`);
    }
    }
  3. Invalid date format:

    // Dates must be ISO 8601 format
    const dueDate = new Date(originalDate).toISOString().split('T')[0];
    // Result: "2024-01-15"
  4. Invalid email format:

    const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    if (!emailRegex.test(debtorEmail)) {
    throw new Error('Invalid email format');
    }

Issue: "Duplicate case detected"

Symptoms:

  • 409 Conflict responses
  • "Case already exists" error
  • Cannot create case for same debtor/invoice

Solutions:

  1. Check for existing cases:

    async function createCaseIfNotExists(caseData) {
    // Search for existing case
    const existing = await debituraClient.getCases({
    referenceNumber: caseData.invoiceNumber
    });

    if (existing.cases.length > 0) {
    console.log('Case already exists:', existing.cases[0].caseId);
    return existing.cases[0];
    }

    return await debituraClient.createCase(caseData);
    }
  2. Handle duplicates gracefully:

    try {
    const newCase = await createCase(caseData);
    return newCase;
    } catch (error) {
    if (error.statusCode === 409) {
    // Duplicate - retrieve existing case
    const existing = await getCaseByReference(caseData.invoiceNumber);
    return existing;
    }
    throw error;
    }

Payment Recording Issues

Issue: "Payment amount exceeds remaining balance"

Symptoms:

  • 400 Bad Request when recording payment
  • "Amount exceeds outstanding balance" error

Solutions:

  1. Check current balance first:

    async function recordPaymentSafely(caseId, paymentData) {
    const caseDetails = await debituraClient.getCase(caseId);

    if (paymentData.amount > caseDetails.remainingBalance) {
    // Adjust payment amount or handle overpayment
    console.warn('Payment exceeds balance, adjusting amount');
    paymentData.amount = caseDetails.remainingBalance;
    }

    return await debituraClient.recordPayment(caseId, paymentData);
    }
  2. Handle partial payments:

    const payment = {
    amount: Math.min(paymentAmount, caseDetails.remainingBalance),
    isPartial: paymentAmount < caseDetails.remainingBalance
    };

Issue: "Payment date in the future"

Symptoms:

  • Validation error on payment date
  • Payment not recorded

Solution:

// Ensure payment date is not in the future
const paymentDate = new Date(originalDate);
const today = new Date();

if (paymentDate > today) {
console.warn('Payment date in future, using today');
paymentData.paymentDate = today.toISOString().split('T')[0];
}

Webhook Issues

Issue: "Webhook deliveries failing"

Symptoms:

  • Webhooks marked as failed in logs
  • Not receiving webhook events
  • Timeout errors

Solutions:

  1. Respond quickly:

    app.post('/webhooks/debitura', (req, res) => {
    // Acknowledge immediately (within 5 seconds)
    res.status(200).send('OK');

    // Process asynchronously
    processWebhook(req.body).catch(console.error);
    });
  2. Check endpoint accessibility:

    # Test webhook endpoint is accessible
    curl -X POST https://your-app.com/webhooks/debitura \
    -H "Content-Type: application/json" \
    -d '{"test": true}'
  3. Verify HTTPS certificate:

    # Check SSL certificate is valid
    openssl s_client -connect your-app.com:443 -servername your-app.com
  4. Review firewall rules:

    • Ensure Debitura IPs are not blocked
    • Check application firewall settings
    • Verify load balancer configuration

Issue: "Invalid webhook signature"

Symptoms:

  • Signature verification fails
  • 401 responses to webhook deliveries

Solutions:

  1. Verify signature correctly:

    const crypto = require('crypto');

    function verifySignature(payload, signature, secret) {
    // Use raw body, not parsed JSON
    const expectedSignature = crypto
    .createHmac('sha256', secret)
    .update(payload) // Raw string, not object
    .digest('hex');

    return signature === expectedSignature;
    }

    // Express configuration
    app.use('/webhooks', express.raw({ type: 'application/json' }));
  2. Check webhook secret:

    // Ensure using correct webhook secret
    const secret = process.env.DEBITURA_WEBHOOK_SECRET;
    if (!secret) {
    console.error('DEBITURA_WEBHOOK_SECRET not configured');
    }

Rate Limiting

Issue: "Rate limit exceeded"

Symptoms:

  • 429 Too Many Requests responses
  • "Rate limit exceeded" errors
  • Requests being throttled

Solutions:

  1. Implement exponential backoff:

    async function requestWithRetry(endpoint, maxRetries = 3) {
    for (let i = 0; i < maxRetries; i++) {
    try {
    return await debituraClient.request(endpoint);
    } catch (error) {
    if (error.statusCode === 429) {
    const delay = Math.pow(2, i) * 1000;
    console.log(`Rate limited, waiting ${delay}ms`);
    await new Promise(resolve => setTimeout(resolve, delay));
    continue;
    }
    throw error;
    }
    }
    throw new Error('Max retries exceeded');
    }
  2. Implement request queuing:

    class RateLimitedClient {
    constructor(requestsPerSecond) {
    this.queue = [];
    this.processing = false;
    this.interval = 1000 / requestsPerSecond;
    }

    async request(endpoint) {
    return new Promise((resolve, reject) => {
    this.queue.push({ endpoint, resolve, reject });
    this.processQueue();
    });
    }

    async processQueue() {
    if (this.processing || this.queue.length === 0) return;

    this.processing = true;
    const { endpoint, resolve, reject } = this.queue.shift();

    try {
    const result = await debituraClient.request(endpoint);
    resolve(result);
    } catch (error) {
    reject(error);
    }

    setTimeout(() => {
    this.processing = false;
    this.processQueue();
    }, this.interval);
    }
    }
  3. Use batch endpoints:

    // Instead of creating cases individually
    for (const data of casesData) {
    await createCase(data); // Don't do this
    }

    // Use batch endpoint if available
    await createCasesBatch(casesData);

Debugging Tips

Enable Debug Logging

// Enable detailed logging
const DEBUG = process.env.DEBUG === 'true';

async function request(endpoint, options) {
if (DEBUG) {
console.log('Request:', {
endpoint,
method: options.method,
headers: options.headers,
body: options.body
});
}

const response = await fetch(endpoint, options);

if (DEBUG) {
console.log('Response:', {
status: response.status,
headers: Object.fromEntries(response.headers.entries())
});
}

return response;
}

Validate Requests Before Sending

function validateCaseData(caseData) {
const errors = [];

if (!caseData.debtorName || caseData.debtorName.length < 2) {
errors.push('Debtor name must be at least 2 characters');
}

if (caseData.principalAmount <= 0) {
errors.push('Principal amount must be greater than 0');
}

if (!['DKK', 'EUR', 'USD'].includes(caseData.currency)) {
errors.push('Invalid currency code');
}

const dueDate = new Date(caseData.dueDate);
if (dueDate > new Date()) {
errors.push('Due date cannot be in the future');
}

if (errors.length > 0) {
throw new Error(`Validation failed:\n${errors.join('\n')}`);
}

return true;
}

Test in Sandbox Environment

// Use sandbox for testing
const baseUrl = process.env.NODE_ENV === 'production'
? 'https://api.debitura.com'
: 'https://sandbox-api.debitura.com';

const client = new DebituraClient({
apiKey: process.env.DEBITURA_API_KEY,
apiSecret: process.env.DEBITURA_API_SECRET,
baseUrl
});

Performance Optimization

Reduce API Calls

  1. Cache frequently accessed data:

    const caseCache = new Map();

    async function getCaseCached(caseId, ttl = 60000) {
    const cached = caseCache.get(caseId);

    if (cached && Date.now() - cached.timestamp < ttl) {
    return cached.data;
    }

    const data = await debituraClient.getCase(caseId);
    caseCache.set(caseId, { data, timestamp: Date.now() });

    return data;
    }
  2. Use webhooks instead of polling:

    // Don't poll for status changes
    setInterval(async () => {
    const cases = await getCases(); // Avoid this
    }, 60000);

    // Use webhooks instead
    app.post('/webhooks/debitura', handleWebhook);
  3. Batch operations when possible:

    // Get multiple cases efficiently
    const cases = await debituraClient.getCases({
    caseIds: ['id1', 'id2', 'id3'].join(',')
    });

Getting Help

Support Resources

  1. API Documentation: API Reference
  2. Integration Examples: Integration Examples
  3. Workflow Guides:

Contact Support

If you cannot resolve an issue:

  1. Gather information:

    • API request details
    • Response codes and error messages
    • Timestamps
    • Case IDs or reference numbers
    • Environment (test/production)
  2. Check status page:

    • Visit status.debitura.com
    • Check for ongoing incidents
    • Review scheduled maintenance
  3. Contact support:

Report Bugs

To report bugs:

  1. Verify issue in sandbox environment
  2. Provide minimal reproduction case
  3. Include API version and client library versions
  4. Submit detailed bug report with examples

Error Code Reference

Common Error Codes

CodeMeaningSolution
400Bad RequestCheck request validation, review required fields
401UnauthorizedVerify API credentials, check token expiry
403ForbiddenCheck permissions, verify API key scope
404Not FoundVerify case ID, check resource exists
409ConflictCheck for duplicate cases, review business rules
422Unprocessable EntityFix validation errors in request data
429Too Many RequestsImplement rate limiting, add retry logic
500Internal Server ErrorRetry request, contact support if persists
503Service UnavailableCheck status page, retry with backoff

Error Response Format

{
"error": {
"code": "VALIDATION_ERROR",
"message": "Invalid debtor information",
"details": [
{
"field": "debtorCvr",
"message": "CVR number must be 8 digits"
}
],
"requestId": "req_123456"
}
}

For urgent production issues, contact our 24/7 support line. See your account dashboard for contact details.