Skip to main content
POST
/
transactions
/
filter
curl -X POST https://api.blnkfinance.com/transactions/filter \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{
    "filters": [
      {
        "field": "status",
        "operator": "eq",
        "value": "APPLIED"
      }
    ],
    "limit": 20,
    "offset": 0
  }'
[
  {
    "transaction_id": "txn_a1b2c3d4e5f6",
    "source": "bln_src123",
    "destination": "bln_dst456",
    "reference": "order-12345",
    "amount": 100.50,
    "precise_amount": "10050",
    "currency": "USD",
    "status": "APPLIED",
    "created_at": "2024-01-15T10:30:00Z"
  }
]
Filter transactions using advanced query capabilities with JSON request body. This endpoint provides more flexibility than the GET /transactions endpoint for complex filtering scenarios.

Request Body

filters
array
required
Array of filter conditions to apply. Each filter is an object with field, operator, and value/values.
limit
integer
default:"20"
Number of transactions to return.
offset
integer
default:"0"
Number of transactions to skip for pagination.
include_count
boolean
default:"false"
Include total count of matching transactions in response.

Filter Object Structure

{
  "field": "status",
  "operator": "eq",
  "value": "APPLIED"
}
filter.field
string
required
Field name to filter on. Supported fields:
  • status
  • currency
  • amount
  • source
  • destination
  • reference
  • created_at
  • scheduled_for
  • effective_date
  • inflight
  • parent_transaction
filter.operator
string
required
Comparison operator:
  • eq - Equals
  • ne - Not equals
  • gt - Greater than
  • gte - Greater than or equal
  • lt - Less than
  • lte - Less than or equal
  • in - In list (requires values array)
  • between - Between two values (requires values array with 2 elements)
  • contains - Contains substring (text fields)
filter.value
any
Single value to compare against (for operators: eq, ne, gt, gte, lt, lte, contains).
filter.values
array
Array of values (for operators: in, between).

Response

Without include_count

Returns array of matching transactions.

With include_count

Returns object with data and count:
data
array
Array of matching transactions.
total_count
integer
Total number of transactions matching the filters (ignoring limit/offset).
[
  {
    "transaction_id": "txn_a1b2c3d4e5f6",
    "source": "bln_src123",
    "destination": "bln_dst456",
    "reference": "order-12345",
    "amount": 100.50,
    "precise_amount": "10050",
    "currency": "USD",
    "status": "APPLIED",
    "created_at": "2024-01-15T10:30:00Z"
  }
]
curl -X POST https://api.blnkfinance.com/transactions/filter \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{
    "filters": [
      {
        "field": "status",
        "operator": "eq",
        "value": "APPLIED"
      }
    ],
    "limit": 20,
    "offset": 0
  }'

Filter Examples by Use Case

High-Value Transactions

{
  "filters": [
    {
      "field": "amount",
      "operator": "gte",
      "value": 10000
    },
    {
      "field": "status",
      "operator": "eq",
      "value": "APPLIED"
    }
  ],
  "limit": 100
}

Failed Transactions

{
  "filters": [
    {
      "field": "status",
      "operator": "eq",
      "value": "REJECTED"
    },
    {
      "field": "created_at",
      "operator": "gte",
      "value": "2024-01-01T00:00:00Z"
    }
  ]
}

Pending Inflight Transactions

{
  "filters": [
    {
      "field": "inflight",
      "operator": "eq",
      "value": true
    },
    {
      "field": "status",
      "operator": "eq",
      "value": "INFLIGHT"
    }
  ]
}

Transactions for Specific Balance

{
  "filters": [
    {
      "field": "source",
      "operator": "eq",
      "value": "bln_balance123"
    }
  ]
}

// OR for both source and destination
// Note: API may support OR logic - check documentation

Reference Pattern Match

{
  "filters": [
    {
      "field": "reference",
      "operator": "contains",
      "value": "order-"
    }
  ]
}

Scheduled Transactions

{
  "filters": [
    {
      "field": "status",
      "operator": "eq",
      "value": "SCHEDULED"
    },
    {
      "field": "scheduled_for",
      "operator": "lte",
      "value": "2024-12-31T23:59:59Z"
    }
  ]
}

Multi-Currency Large Transactions

{
  "filters": [
    {
      "field": "currency",
      "operator": "in",
      "values": ["USD", "EUR", "GBP"]
    },
    {
      "field": "amount",
      "operator": "gte",
      "value": 5000
    }
  ],
  "include_count": true
}

Pagination with Count

Use include_count for building pagination UI:
async function getPaginatedTransactions(page, perPage) {
  const response = await fetch('/transactions/filter', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      filters: [
        { field: 'status', operator: 'eq', value: 'APPLIED' }
      ],
      limit: perPage,
      offset: page * perPage,
      include_count: true
    })
  }).then(r => r.json());
  
  return {
    transactions: response.data,
    totalCount: response.total_count,
    totalPages: Math.ceil(response.total_count / perPage),
    currentPage: page
  };
}

// Usage
const page1 = await getPaginatedTransactions(0, 20);
// Returns:
// {
//   transactions: [...20 items...],
//   totalCount: 1523,
//   totalPages: 77,
//   currentPage: 0
// }

Error Responses

error
string
Error message describing what went wrong.

Common Errors

400 Bad Request - Invalid Filter
{
  "error": "invalid operator 'invalid_op' for field 'amount'"
}
400 Bad Request - Missing Value
{
  "error": "filter requires 'value' field for operator 'eq'"
}
400 Bad Request - Invalid Field
{
  "error": "unknown field 'invalid_field'"
}
400 Bad Request - Invalid Date Format
{
  "error": "invalid date format for field 'created_at'"
}

Performance Considerations

Indexed Fields

These fields are typically indexed for fast filtering:
  • status
  • currency
  • source
  • destination
  • created_at
  • reference

Optimization Tips

  1. Filter by indexed fields first - Put indexed field filters at the beginning
  2. Use date ranges - Limit date ranges to reduce scan size
  3. Avoid contains on large datasets - Use exact matches when possible
  4. Limit page size - Keep limit under 100 for best performance
  5. Cache results - Cache frequently accessed filter results

Use Cases

Transaction Report Generation

async function generateMonthlyReport(year, month) {
  const startDate = new Date(year, month - 1, 1);
  const endDate = new Date(year, month, 0, 23, 59, 59);
  
  const result = await fetch('/transactions/filter', {
    method: 'POST',
    body: JSON.stringify({
      filters: [
        {
          field: 'created_at',
          operator: 'between',
          values: [startDate.toISOString(), endDate.toISOString()]
        },
        {
          field: 'status',
          operator: 'eq',
          value: 'APPLIED'
        }
      ],
      limit: 10000,  // Large limit for full report
      include_count: true
    })
  }).then(r => r.json());
  
  // Generate report from result.data
  const report = {
    period: `${year}-${month}`,
    total_transactions: result.total_count,
    total_volume: result.data.reduce((sum, t) => sum + t.amount, 0),
    transactions: result.data
  };
  
  return report;
}

Fraud Detection Query

def detect_suspicious_transactions():
    # Find high-value transactions in short time
    response = requests.post('/transactions/filter', json={
        'filters': [
            {
                'field': 'amount',
                'operator': 'gte',
                'value': 10000
            },
            {
                'field': 'created_at',
                'operator': 'gte',
                'value': (datetime.now() - timedelta(hours=1)).isoformat()
            },
            {
                'field': 'status',
                'operator': 'eq',
                'value': 'APPLIED'
            }
        ],
        'limit': 1000
    }).json()
    
    # Group by source to find multiple large transactions
    by_source = {}
    for txn in response:
        source = txn['source']
        if source not in by_source:
            by_source[source] = []
        by_source[source].append(txn)
    
    # Flag sources with 3+ large transactions in 1 hour
    suspicious = {
        source: txns 
        for source, txns in by_source.items() 
        if len(txns) >= 3
    }
    
    return suspicious

Balance Activity Summary

async function getBalanceActivity(balanceId, startDate, endDate) {
  // Get debits (as source)
  const debits = await fetch('/transactions/filter', {
    method: 'POST',
    body: JSON.stringify({
      filters: [
        { field: 'source', operator: 'eq', value: balanceId },
        { field: 'status', operator: 'eq', value: 'APPLIED' },
        { field: 'created_at', operator: 'between', values: [startDate, endDate] }
      ],
      include_count: true
    })
  }).then(r => r.json());
  
  // Get credits (as destination)
  const credits = await fetch('/transactions/filter', {
    method: 'POST',
    body: JSON.stringify({
      filters: [
        { field: 'destination', operator: 'eq', value: balanceId },
        { field: 'status', operator: 'eq', value: 'APPLIED' },
        { field: 'created_at', operator: 'between', values: [startDate, endDate] }
      ],
      include_count: true
    })
  }).then(r => r.json());
  
  return {
    balance_id: balanceId,
    period: { start: startDate, end: endDate },
    debits: {
      count: debits.total_count,
      total: debits.data.reduce((sum, t) => sum + t.amount, 0),
      transactions: debits.data
    },
    credits: {
      count: credits.total_count,
      total: credits.data.reduce((sum, t) => sum + t.amount, 0),
      transactions: credits.data
    }
  };
}

Reconciliation Helper

def reconcile_transactions(external_refs):
    # Find all transactions matching external references
    response = requests.post('/transactions/filter', json={
        'filters': [
            {
                'field': 'reference',
                'operator': 'in',
                'values': external_refs
            }
        ],
        'limit': len(external_refs)
    }).json()
    
    # Match with external records
    matched = set()
    unmatched_external = set(external_refs)
    
    for txn in response:
        matched.add(txn['reference'])
        unmatched_external.discard(txn['reference'])
    
    # Find unmatched in Blnk
    unmatched_blnk = set(external_refs) - matched
    
    return {
        'matched_count': len(matched),
        'unmatched_in_blnk': list(unmatched_blnk),
        'unmatched_external': list(unmatched_external),
        'transactions': response
    }

Best Practices

  1. Use POST /transactions/filter for complex queries - Better than GET with query params
  2. Enable include_count for pagination - Essential for building pagination UI
  3. Filter by date ranges - Always include date filters to limit scan size
  4. Combine filters efficiently - Use multiple filters to narrow results
  5. Handle large result sets - Use pagination for queries returning >1000 records
  6. Cache filter results - Cache commonly used filter combinations
  7. Use appropriate operators - Choose the right operator for each field type

Filter vs List Comparison

FeatureGET /transactionsPOST /transactions/filter
MethodGETPOST
FiltersQuery parametersJSON body
ComplexitySimple (1-3 filters)Complex (many filters)
CountNoYes (with include_count)
ShareableYes (URL)No
Best forSimple queries, bookmarksComplex queries, apps

Build docs developers (and LLMs) love