Skip to main content

Getting Started with Link Core

This guide will help you integrate with the Link Core API for transaction processing, balance management, and asset operations.

Authentication

Link Core is designed to be accessed through the Link Dashboard, which handles authentication.

Production Architecture:

User/Client
↓ (authenticates)
Link Dashboard (Next.js)
↓ (validates session)
Auth Server/BFF (Port 4000)
↓ (proxies authenticated requests)
Link Core Service (Port 3000)

Authentication Flow:

  1. Users authenticate with the Link Dashboard
  2. Auth Server validates JWT tokens and session cookies
  3. Authenticated requests are forwarded to Link Core
  4. Link Core processes the request (no auth check at service level)
  5. Response flows back through the chain

Direct Service Access (Development Only):

  • Local development: http://localhost:3000 (no authentication)
  • Ensure network isolation in development/test environments
  • Production deployments should only allow access through Auth Server

Base URLs

  • Production: https://api.ledgerlink.ai/v1
  • Sandbox: https://sandbox-api.ledgerlink.ai/v1
  • Local Development: http://localhost:3000 (default port)

Quick Start

1. List All Transactions

Through Link Dashboard (Production):

curl -X GET "https://your-dashboard.ledgerlink.ai/api/link-core/v1/transactions" \
-H "Cookie: session_cookie_here"

Direct to Service (Development):

curl -X GET "http://localhost:3000/transactions"

Response:

[
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"type": "DEPOSIT",
"status": "COMPLETED",
"amount": "1000.00",
"assetId": "btc-asset-id",
"customerId": "customer-123",
"createdAt": "2025-11-20T17:00:00.000Z",
"updatedAt": "2025-11-20T17:05:00.000Z"
}
]

2. Get a Specific Transaction

curl -X GET "http://localhost:3000/transactions/550e8400-e29b-41d4-a716-446655440000"

3. Request a Withdrawal

curl -X POST "http://localhost:3000/transactions/withdrawal" \
-H "Content-Type: application/json" \
-d '{
"customerId": "customer-123",
"assetId": "btc-asset-id",
"amount": "0.5",
"destinationAddress": "bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh"
}'

Response:

{
"id": "tx-withdrawal-123",
"type": "WITHDRAWAL",
"status": "PENDING",
"amount": "0.5",
"assetId": "btc-asset-id",
"customerId": "customer-123",
"destinationAddress": "bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh",
"createdAt": "2025-11-20T18:00:00.000Z"
}

4. Get Customer Balances

curl -X GET "http://localhost:3000/balances/customer/customer-123"

Response:

[
{
"assetId": "btc-asset-id",
"assetCode": "BTC",
"available": "2.5",
"frozen": "0.5",
"total": "3.0"
},
{
"assetId": "eth-asset-id",
"assetCode": "ETH",
"available": "10.0",
"frozen": "0.0",
"total": "10.0"
}
]

5. Create a Digital Asset

curl -X POST "http://localhost:3000/assets" \
-H "Content-Type: application/json" \
-d '{
"code": "BTC",
"name": "Bitcoin",
"decimals": 8,
"blockchain": "bitcoin",
"contractAddress": null
}'

Transaction Lifecycle

Deposit Flow

  1. Blockchain Event Detected

    • Blockchain Listener detects incoming transaction
    • Transaction created with status PENDING
  2. Awaiting External Screening

    • Transaction awaits external AML/compliance screening
    • External system (outside LedgerLink) performs checks
    • Status remains PENDING until screening callback received
  3. Screening Completed (via webhook callback)

    • External system calls POST /transactions/complete-screening
    • If approved → Status APPROVED, balance updated
    • If rejected → Status FROZEN, awaits manual review
  4. Manual Review (if frozen)

    • POST /transactions/:id/approve-frozen-deposit → Complete processing
    • POST /transactions/:id/reject-frozen-deposit → Reject and notify customer
  5. Completion

    • Status COMPLETED
    • Balance available to customer

Withdrawal Flow

  1. Customer Requests Withdrawal

    • POST /transactions/withdrawal
    • Transaction created with status PENDING
  2. Awaiting External Screening

    • Transaction awaits external AML/compliance screening
    • External system (outside LedgerLink) performs checks
    • Status remains PENDING until screening callback received
  3. Screening Completed (via webhook callback)

    • External system calls POST /transactions/complete-screening
    • If approved → Blockchain transaction initiated
    • If rejected → Status FROZEN, awaits manual review
  4. Manual Review (if frozen)

    • POST /transactions/:id/approve-frozen-withdrawal → Initiate blockchain transaction
    • POST /transactions/:id/reject-frozen-withdrawal → Reject and refund
  5. Blockchain Execution

    • Wallet Manager executes blockchain transaction
    • Status updated as transaction confirms
  6. Completion

    • Status COMPLETED
    • Balance deducted from customer account

Transaction Statuses

  • PENDING: Transaction created, awaiting external screening callback
  • FROZEN: Flagged by external screening, requires manual review
  • APPROVED: Approved (either automatically or after manual review), processing
  • COMPLETED: Fully processed
  • REJECTED: Rejected by external screening or manual review
  • FAILED: Processing failed

Note: There is no separate "SCREENING" status. Transactions remain in PENDING status while external AML/compliance systems perform their checks and call back via the /transactions/complete-screening webhook.

Balance Queries

Filter by Asset

curl -X GET "http://localhost:3000/balances/customer/customer-123?filter[assetCode]=BTC"

Get Account-Specific Balances

curl -X GET "http://localhost:3000/balances/account/account-456"

Local Development Setup

To run Link Core locally:

# Install Node.js (v16+)
nvm install
nvm use

# Start PostgreSQL with Docker
npm run docker

# Install dependencies
npm install

# Configure environment
cp .env.example .env
# Edit .env with your configuration

# Run database migrations
npm run migration:run

# Start the server
npm run start:dev

Access Swagger docs at: http://localhost:3000/api

Integration Patterns

Dashboard Integration

// Example: Fetch customer balances from Link Core
async function getCustomerBalances(customerId: string) {
// In production, call through Auth Server BFF:
const response = await fetch(`/api/link-core/v1/balances/customer/${customerId}`, {
credentials: 'include', // Include session cookies
});

if (!response.ok) {
throw new Error(`Failed to fetch balances: ${response.statusText}`);
}

return response.json();
}

// Example: Request withdrawal
async function requestWithdrawal(data: WithdrawalRequest) {
const response = await fetch('/api/link-core/v1/transactions/withdrawal', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
credentials: 'include',
body: JSON.stringify(data),
});

return response.json();
}

Monitoring Transaction Status

// Poll transaction status
async function monitorTransaction(transactionId: string) {
const checkStatus = async () => {
const response = await fetch(`/api/link-core/v1/transactions/${transactionId}`);
const transaction = await response.json();

if (transaction.status === 'COMPLETED') {
console.log('Transaction completed!');
return transaction;
} else if (transaction.status === 'FAILED' || transaction.status === 'REJECTED') {
console.error('Transaction failed:', transaction);
return transaction;
}

// Still processing, check again in 5 seconds
setTimeout(checkStatus, 5000);
};

return checkStatus();
}

Error Handling

Link Core returns standard HTTP status codes:

  • 200 OK: Request successful
  • 201 Created: Resource created successfully
  • 400 Bad Request: Invalid parameters
  • 401 Unauthorized: Authentication failed (handled by Auth Server)
  • 404 Not Found: Resource not found
  • 409 Conflict: Resource conflict (e.g., duplicate transaction)
  • 422 Unprocessable Entity: Validation errors
  • 500 Internal Server Error: Unexpected error

See Error Handling Guide for details.

Job Processing

Link Core uses Bull queues for background processing:

Screening Complete Queue

Processes transactions after screening approval:

  • Updates transaction status
  • Updates customer balances
  • Notifies downstream services

Omnibus Balance Jobs

Monitors omnibus wallet balances:

  • Tracks omnibus account balances
  • Alerts on low balance conditions
  • Ensures sufficient liquidity

Integration with Other Services

// Get asset price for transaction valuation
async function getAssetPrice(assetCode: string): Promise<number> {
const response = await fetch('/api/link-quote/v1/rates', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ assetCode }),
});

const data = await response.json();
return data.rate;
}

Link Core automatically logs events to Link Tracker:

  • Transaction state changes
  • Balance updates
  • Error conditions
  • Screening results

Next Steps


Need Help? Contact helpdesk@ledgerlink.ai