Skip to main content
GET
/
transactions
/
:id
/
lineage
curl -X GET https://api.blnkfinance.com/transactions/txn_a1b2c3d4e5f6/lineage \
  -H "Authorization: Bearer YOUR_API_KEY"
{
  "transaction_id": "txn_a1b2c3d4e5f6",
  "lineage": [
    {
      "source_identity_id": "identity_customer_123",
      "destination_identity_id": "identity_merchant_456",
      "amount": 100.00,
      "precise_amount": "10000",
      "transaction_id": "txn_a1b2c3d4e5f6",
      "created_at": "2024-01-15T10:00:00Z",
      "currency": "USD"
    },
    {
      "source_identity_id": "identity_merchant_456",
      "destination_identity_id": "identity_supplier_789",
      "amount": 75.00,
      "precise_amount": "7500",
      "transaction_id": "txn_b2c3d4e5f6g7",
      "created_at": "2024-01-15T11:00:00Z",
      "currency": "USD"
    }
  ]
}
Retrieve the fund lineage history for a transaction, showing how funds have flowed through the system. This is useful for tracking the origin and movement of funds for compliance, auditing, and fund tracking purposes.

Path Parameters

id
string
required
The transaction ID for which to retrieve lineage information.

Response

Returns lineage information showing fund flow history.
transaction_id
string
The transaction ID being queried.
lineage
array
Array of fund lineage records showing how funds have moved.
lineage[].source_identity_id
string
Identity ID of the source balance.
lineage[].destination_identity_id
string
Identity ID of the destination balance.
lineage[].amount
number
Amount transferred in this lineage step.
lineage[].precise_amount
string
Exact amount in minor units.
lineage[].transaction_id
string
Transaction ID for this lineage step.
lineage[].created_at
string
When this lineage step occurred.
{
  "transaction_id": "txn_a1b2c3d4e5f6",
  "lineage": [
    {
      "source_identity_id": "identity_customer_123",
      "destination_identity_id": "identity_merchant_456",
      "amount": 100.00,
      "precise_amount": "10000",
      "transaction_id": "txn_a1b2c3d4e5f6",
      "created_at": "2024-01-15T10:00:00Z",
      "currency": "USD"
    },
    {
      "source_identity_id": "identity_merchant_456",
      "destination_identity_id": "identity_supplier_789",
      "amount": 75.00,
      "precise_amount": "7500",
      "transaction_id": "txn_b2c3d4e5f6g7",
      "created_at": "2024-01-15T11:00:00Z",
      "currency": "USD"
    }
  ]
}
curl -X GET https://api.blnkfinance.com/transactions/txn_a1b2c3d4e5f6/lineage \
  -H "Authorization: Bearer YOUR_API_KEY"

Fund Lineage Tracking

Fund lineage tracks how money moves through your system across multiple transactions and identities. This is critical for:
  • Compliance: AML/KYC requirements for tracking fund origins
  • Auditing: Complete audit trails of fund movement
  • Reconciliation: Understanding complex multi-party transactions
  • Analytics: Identifying fund flow patterns

How Lineage Works

  1. Balance Creation: When creating a balance, set track_fund_lineage: true and provide an identity_id
POST /balances
{
  "ledger_id": "ldg_123",
  "currency": "USD",
  "identity_id": "identity_customer_123",
  "track_fund_lineage": true
}
  1. Transaction Recording: Lineage is automatically tracked when transactions occur between lineage-enabled balances
POST /transactions
{
  "amount": 100.00,
  "source": "bln_customer",  // Has identity_customer_123
  "destination": "bln_merchant",  // Has identity_merchant_456
  "reference": "payment-001",
  "currency": "USD"
}
  1. Lineage Retrieval: Query any transaction to see its fund flow history
GET /transactions/txn_xyz/lineage

Lineage Example Flow

Scenario: Customer → Merchant → Supplier

Step 1: Customer pays merchant
// Transaction 1: Customer to Merchant
const payment = await createTransaction({
  amount: 100.00,
  source: 'bln_customer',  // identity_customer_123
  destination: 'bln_merchant',  // identity_merchant_456
  reference: 'order-001'
});

// Lineage for txn_payment:
// [
//   {
//     source_identity: 'identity_customer_123',
//     destination_identity: 'identity_merchant_456',
//     amount: 100.00,
//     transaction_id: 'txn_payment'
//   }
// ]
Step 2: Merchant pays supplier
// Transaction 2: Merchant to Supplier
const payout = await createTransaction({
  amount: 75.00,
  source: 'bln_merchant',  // identity_merchant_456
  destination: 'bln_supplier',  // identity_supplier_789
  reference: 'payout-001'
});

// Lineage for txn_payout shows full chain:
// [
//   {
//     source_identity: 'identity_customer_123',
//     destination_identity: 'identity_merchant_456',
//     amount: 100.00,
//     transaction_id: 'txn_payment'
//   },
//   {
//     source_identity: 'identity_merchant_456',
//     destination_identity: 'identity_supplier_789',
//     amount: 75.00,
//     transaction_id: 'txn_payout'
//   }
// ]
The lineage shows that the 75paidtothesupplierultimatelycamefromthecustomers75 paid to the supplier ultimately came from the customer's 100 payment.

Allocation Strategies

Blnk supports different strategies for allocating funds when tracking lineage:

FIFO (First-In-First-Out)

Funds received first are spent first.
{
  "allocation_strategy": "FIFO"
}
Example:
  • Receive $100 from Customer A
  • Receive $50 from Customer B
  • Pay $75 to Supplier
Lineage: $75 comes from Customer A (using oldest funds first)

LIFO (Last-In-First-Out)

Funds received last are spent first.
{
  "allocation_strategy": "LIFO"
}
Example:
  • Receive $100 from Customer A
  • Receive $50 from Customer B
  • Pay $75 to Supplier
Lineage: 50fromCustomerB,50 from Customer B, 25 from Customer A (using newest funds first)

PROPORTIONAL

Funds are allocated proportionally based on balance composition.
{
  "allocation_strategy": "PROPORTIONAL"
}
Example:
  • Receive $100 from Customer A (66.67% of balance)
  • Receive $50 from Customer B (33.33% of balance)
  • Pay $75 to Supplier
Lineage: 50fromCustomerA(66.6750 from Customer A (66.67% of 75), 25fromCustomerB(33.3325 from Customer B (33.33% of 75)

Error Responses

error
string
Error message describing what went wrong.

Common Errors

400 Bad Request - Missing ID
{
  "error": "id is required. pass id in the route /:id"
}
400 Bad Request - Transaction Not Found
{
  "error": "transaction not found"
}
400 Bad Request - Lineage Not Tracked
{
  "error": "lineage tracking not enabled for this transaction"
}
Returned when the transaction’s balances don’t have track_fund_lineage enabled.

Use Cases

Compliance Reporting

Track fund origins for AML compliance:
async function checkFundOrigin(transactionId, suspiciousIdentity) {
  const lineage = await getTransactionLineage(transactionId);
  
  // Check if funds originated from suspicious identity
  const hasSuspiciousOrigin = lineage.lineage.some(
    step => step.source_identity_id === suspiciousIdentity
  );
  
  if (hasSuspiciousOrigin) {
    await flagForReview(transactionId, {
      reason: 'suspicious_origin',
      identity: suspiciousIdentity,
      lineage: lineage
    });
  }
  
  return hasSuspiciousOrigin;
}

Marketplace Fee Attribution

Track which customer payments generated fees:
def attribute_fees_to_customers(fee_transaction_id):
    lineage = get_transaction_lineage(fee_transaction_id)
    
    # Group by originating customer
    customer_contributions = {}
    
    for step in lineage['lineage']:
        # First source_identity is the customer
        if step == lineage['lineage'][0]:
            customer_id = step['source_identity_id']
            amount = Decimal(step['precise_amount'])
            
            if customer_id not in customer_contributions:
                customer_contributions[customer_id] = Decimal('0')
            
            customer_contributions[customer_id] += amount
    
    return customer_contributions

Supply Chain Tracking

Track payments through supply chain:
async function traceSupplyChainPayment(supplierPaymentId) {
  const lineage = await getTransactionLineage(supplierPaymentId);
  
  // Build payment chain
  const chain = lineage.lineage.map((step, index) => ({
    step: index + 1,
    from: step.source_identity_id,
    to: step.destination_identity_id,
    amount: step.amount,
    transaction: step.transaction_id,
    date: step.created_at
  }));
  
  console.log('Payment chain:');
  chain.forEach(step => {
    console.log(`${step.step}. ${step.from}${step.to}: $${step.amount}`);
  });
  
  return chain;
}

// Output:
// Payment chain:
// 1. identity_customer_123 → identity_merchant_456: $100.00
// 2. identity_merchant_456 → identity_supplier_789: $75.00
// 3. identity_supplier_789 → identity_manufacturer_012: $50.00

Revenue Attribution

Attribute revenue to original sources:
def analyze_revenue_sources(period_start, period_end):
    # Get all revenue transactions in period
    revenue_txns = get_transactions(
        destination_eq='revenue_account',
        created_at_between=f'{period_start}|{period_end}'
    )
    
    source_attribution = {}
    
    for txn in revenue_txns:
        lineage = get_transaction_lineage(txn['transaction_id'])
        
        for step in lineage['lineage']:
            # Track first source (origin)
            if step == lineage['lineage'][0]:
                source_id = step['source_identity_id']
                amount = Decimal(step['precise_amount'])
                
                if source_id not in source_attribution:
                    source_attribution[source_id] = {
                        'total_amount': Decimal('0'),
                        'transaction_count': 0
                    }
                
                source_attribution[source_id]['total_amount'] += amount
                source_attribution[source_id]['transaction_count'] += 1
    
    return source_attribution

Fraud Detection

Detect suspicious fund flows:
async function detectCircularFlows(transactionId) {
  const lineage = await getTransactionLineage(transactionId);
  
  // Check for circular flows (A → B → A)
  const identities = new Set();
  let hasCircular = false;
  
  for (const step of lineage.lineage) {
    if (identities.has(step.destination_identity_id)) {
      // Destination already appeared as source/destination
      hasCircular = true;
      
      await flagTransaction(transactionId, {
        reason: 'circular_flow_detected',
        identity: step.destination_identity_id,
        lineage: lineage
      });
    }
    
    identities.add(step.source_identity_id);
    identities.add(step.destination_identity_id);
  }
  
  return hasCircular;
}

Visualizing Lineage

Text-based Flow Diagram

function visualizeLineage(lineage) {
  console.log('Fund Flow Diagram:\n');
  
  lineage.lineage.forEach((step, index) => {
    const arrow = index === 0 ? '' : '      ↓\n';
    console.log(
      `${arrow}` +
      `Step ${index + 1}: ${step.source_identity_id}\n` +
      `        → $${step.amount}\n` +
      `        → ${step.destination_identity_id}\n` +
      `        (${step.transaction_id})\n` +
      `        ${step.created_at}`
    );
  });
}

// Output:
// Fund Flow Diagram:
//
// Step 1: identity_customer_123
//         → $100.00
//         → identity_merchant_456
//         (txn_abc123)
//         2024-01-15T10:00:00Z
//       ↓
// Step 2: identity_merchant_456
//         → $75.00
//         → identity_supplier_789
//         (txn_def456)
//         2024-01-15T11:00:00Z

Graph Data Structure

def build_lineage_graph(transaction_id):
    lineage = get_transaction_lineage(transaction_id)
    
    # Build graph structure
    graph = {
        'nodes': [],
        'edges': []
    }
    
    nodes_set = set()
    
    for step in lineage['lineage']:
        source = step['source_identity_id']
        dest = step['destination_identity_id']
        
        # Add nodes
        if source not in nodes_set:
            graph['nodes'].append({'id': source, 'label': source})
            nodes_set.add(source)
        
        if dest not in nodes_set:
            graph['nodes'].append({'id': dest, 'label': dest})
            nodes_set.add(dest)
        
        # Add edge
        graph['edges'].append({
            'from': source,
            'to': dest,
            'label': f"${step['amount']}",
            'transaction_id': step['transaction_id']
        })
    
    return graph

# Can be used with visualization libraries like:
# - D3.js for web visualization
# - NetworkX for Python graph analysis
# - Cytoscape for interactive graphs

Best Practices

  1. Enable lineage at balance creation - Set track_fund_lineage: true and provide identity_id
  2. Choose appropriate allocation strategy - FIFO for compliance, PROPORTIONAL for fair attribution
  3. Index identity IDs - Store and index identity IDs for fast lineage queries
  4. Cache lineage results - Cache lineage data for frequently accessed transactions
  5. Monitor lineage depth - Very deep lineage chains may indicate circular flows or issues
  6. Use for compliance - Leverage lineage for AML/KYC and regulatory reporting
  7. Document identity IDs - Maintain clear mapping between identity IDs and real entities

Build docs developers (and LLMs) love