Skip to main content

Error Handling

This guide explains how to handle errors when integrating with the Link Core API.

Standard Error Response Format​

All error responses follow a consistent structure:

{
"statusCode": 404,
"message": "Transaction with ID 550e8400-e29b-41d4-a716-446655440000 not found",
"error": "Not Found",
"timestamp": "2025-11-20T17:00:00.000Z",
"path": "/transactions/550e8400-e29b-41d4-a716-446655440000"
}

HTTP Status Codes​

Success Codes (2xx)​

CodeStatusDescription
200OKRequest successful
201CreatedResource successfully created

Client Error Codes (4xx)​

CodeStatusDescription
400Bad RequestInvalid request parameters or body
401UnauthorizedAuthentication failed (handled by Auth Server/Dashboard)
404Not FoundResource not found (transaction, asset, etc.)
409ConflictResource conflict (duplicate transaction, etc.)
422Unprocessable EntityValidation errors
429Too Many RequestsRate limit exceeded (handled by Auth Server/Dashboard)

Note:

  • Authentication (401) and Rate Limiting (429) are handled by the Link Dashboard's Auth Server
  • 403 (Forbidden) is not currently implemented (no RBAC/permissions)
  • Link Core service itself returns: 400, 404, 409, 422, and 5xx errors

Server Error Codes (5xx)​

CodeStatusDescription
500Internal Server ErrorUnexpected server error
502Bad GatewayUpstream service error
503Service UnavailableService temporarily unavailable
504Gateway TimeoutRequest timeout

Common Error Scenarios​

1. Transaction Not Found​

Scenario: Requesting a non-existent transaction

GET /transactions/invalid-id

Error Response:

{
"statusCode": 404,
"message": "Transaction with ID invalid-id not found",
"error": "Not Found"
}

Solution:

  • Verify transaction ID is correct
  • Check if transaction exists using GET /transactions

2. Invalid Withdrawal Request​

Scenario: Missing required fields or invalid data

POST /transactions/withdrawal
{
"customerId": "customer-123"
// Missing required fields
}

Error Response:

{
"statusCode": 400,
"message": ["assetId should not be empty", "amount should not be empty"],
"error": "Bad Request"
}

Solution:

  • Include all required fields (customerId, assetId, amount, destinationAddress)
  • Validate data types and formats before sending

3. Insufficient Balance​

Scenario: Withdrawal amount exceeds available balance

Error Response:

{
"statusCode": 400,
"message": "Insufficient balance for withdrawal",
"error": "Bad Request"
}

Solution:

  • Check customer balance before requesting withdrawal
  • Ensure amount doesn't exceed available balance

4. Invalid Transaction Status​

Scenario: Attempting operation on transaction in wrong status

POST /transactions/:id/approve-frozen-deposit
# Transaction is not in FROZEN status

Error Response:

{
"statusCode": 409,
"message": "Transaction is not in FROZEN status",
"error": "Conflict"
}

Solution:

  • Check transaction status before performing operations
  • Only approve/reject transactions in FROZEN status

5. Asset Not Found​

Scenario: Requesting withdrawal with non-existent asset

Error Response:

{
"statusCode": 404,
"message": "Asset with ID asset-123 not found",
"error": "Not Found"
}

Solution:

  • Verify asset ID exists using GET /assets
  • Create asset first if needed

6. Validation Errors​

Scenario: Invalid data format

POST /transactions/withdrawal
{
"customerId": "customer-123",
"assetId": "btc",
"amount": "invalid-amount",
"destinationAddress": "invalid-address"
}

Error Response:

{
"statusCode": 422,
"message": [
"amount must be a valid number",
"destinationAddress must be a valid blockchain address"
],
"error": "Unprocessable Entity"
}

Solution:

  • Validate all input data before sending
  • Use proper data types and formats

Best Practices​

1. Implement Retry Logic​

async function fetchTransactionWithRetry(
id: string,
maxRetries = 3
): Promise<Transaction> {
for (let i = 0; i < maxRetries; i++) {
try {
const response = await fetch(`/api/link-core/v1/transactions/${id}`);

if (!response.ok) {
if (response.status === 404) {
throw new Error('Transaction not found');
}

// Retry on 5xx errors
if (response.status >= 500 && i < maxRetries - 1) {
await sleep(Math.pow(2, i) * 1000); // Exponential backoff
continue;
}
}

return response.json();
} catch (error) {
if (i === maxRetries - 1) throw error;
}
}
}

2. Validate Before Sending​

function validateWithdrawalRequest(request: WithdrawalRequest): void {
if (!request.customerId) {
throw new Error('Customer ID is required');
}

if (!request.assetId) {
throw new Error('Asset ID is required');
}

if (!request.amount || parseFloat(request.amount) <= 0) {
throw new Error('Amount must be greater than zero');
}

if (!request.destinationAddress) {
throw new Error('Destination address is required');
}
}

3. Handle Transaction States​

async function handleTransaction(transactionId: string) {
const transaction = await fetchTransaction(transactionId);

switch (transaction.status) {
case 'PENDING':
console.log('Transaction is pending screening');
break;

case 'SCREENING':
console.log('Transaction is being screened');
break;

case 'FROZEN':
console.log('Transaction requires manual review');
// Notify admin for review
break;

case 'APPROVED':
console.log('Transaction approved, processing...');
break;

case 'COMPLETED':
console.log('Transaction completed');
break;

case 'REJECTED':
console.error('Transaction rejected');
// Notify customer
break;

case 'FAILED':
console.error('Transaction failed');
// Handle failure
break;
}
}

4. Monitor and Alert​

  • Track error rates by status code and endpoint
  • Alert on sustained 5xx errors
  • Monitor transaction failure rates
  • Log errors with full context for debugging
  • Set up health checks for critical flows

Recovery Strategies​

For 5xx Errors (Server Errors)​

  1. Short-term:

    • Retry with exponential backoff
    • Queue failed requests for later retry
    • Show user-friendly error messages
  2. Long-term:

    • Implement circuit breaker pattern
    • Set up fallback mechanisms
    • Monitor and alert on error spikes

For 400 Errors (Bad Request)​

  1. Implement client-side validation
  2. Provide clear error messages to users
  3. Log validation failures for analysis
  4. Update UI to prevent invalid inputs

For 404 Errors (Not Found)​

  1. Verify resource IDs before operations
  2. Handle deleted/non-existent resources gracefully
  3. Provide helpful suggestions (e.g., "Transaction may have been deleted")

For 409 Errors (Conflict)​

  1. Check resource state before operations
  2. Handle state transitions properly
  3. Implement optimistic locking where needed
  4. Retry with updated state

Debug Mode​

Enable detailed logging in local development:

# In .env
NODE_ENV=development
LOG_LEVEL=debug

This will show:

  • Database queries
  • External service calls
  • Transaction state changes
  • Queue job processing
  • Detailed error stack traces

Support​

If errors persist:

  1. Review API documentation and examples
  2. Check JIRA for similar reported issues
  3. Enable debug logging to investigate
  4. Contact helpdesk@ledgerlink.ai with:
    • Timestamp of error
    • Full error response
    • Steps to reproduce
    • Relevant log output

Next: FAQ | API Reference