Reconciliation
Practice example
Run a one-to-one reconciliation with sample transactions and a sample file.
Record ten ledger transactions, upload a sample file, create one matching rule, and read the result.
This walkthrough uses one-to-one, so each external row is compared with one ledger transaction.
You need a Core instance at http://localhost:5001.
Record sample transactions
Post the ten sample transactions with Bulk transactions.
curl -X POST "http://localhost:5001/transactions/bulk" \
-H "X-blnk-key: <api-key>" \
-H "Content-Type: application/json" \
-d '{
"atomic": true,
"inflight": false,
"run_async": false,
"transactions": [
{
"amount": 152.75,
"precision": 100,
"reference": "txn_001",
"description": "Invoice settlement",
"currency": "USD",
"source": "@WorldA",
"allow_overdraft": true,
"destination": "@WorldB"
},
{
"amount": 329.40,
"precision": 100,
"reference": "txn_002",
"description": "Refund processing",
"currency": "USD",
"source": "@WorldB",
"allow_overdraft": true,
"destination": "@WorldA"
},
{
"amount": 87.15,
"precision": 100,
"reference": "txn_003",
"description": "Service charge",
"currency": "USD",
"source": "@WorldA",
"allow_overdraft": true,
"destination": "@WorldB"
},
{
"amount": 413.60,
"precision": 100,
"reference": "txn_004",
"description": "Payment for goods",
"currency": "USD",
"source": "@WorldB",
"allow_overdraft": true,
"destination": "@WorldA"
},
{
"amount": 276.89,
"precision": 100,
"reference": "txn_005",
"description": "Subscription fee",
"currency": "USD",
"source": "@WorldA",
"allow_overdraft": true,
"destination": "@WorldB"
},
{
"amount": 199.99,
"precision": 100,
"reference": "txn_006",
"description": "Expense reimbursement",
"currency": "USD",
"source": "@WorldB",
"allow_overdraft": true,
"destination": "@WorldA"
},
{
"amount": 540.25,
"precision": 100,
"reference": "txn_007",
"description": "Project funding",
"currency": "USD",
"source": "@WorldA",
"allow_overdraft": true,
"destination": "@WorldB"
},
{
"amount": 135.70,
"precision": 100,
"reference": "txn_008",
"description": "Loan repayment",
"currency": "USD",
"source": "@WorldB",
"allow_overdraft": true,
"destination": "@WorldA"
},
{
"amount": 92.80,
"precision": 100,
"reference": "txn_009",
"description": "Freelance payment",
"currency": "USD",
"source": "@WorldA",
"allow_overdraft": true,
"destination": "@WorldB"
},
{
"amount": 480.55,
"precision": 100,
"reference": "txn_010",
"description": "Revenue share",
"currency": "USD",
"source": "@WorldB",
"allow_overdraft": true,
"destination": "@WorldA"
}
]
}'const response = await blnk.Transactions.createBulk({
atomic: true,
inflight: false,
run_async: false,
transactions: [
{
amount: 152.75,
precision: 100,
reference: 'txn_001',
description: 'Invoice settlement',
currency: 'USD',
source: '@WorldA',
allow_overdraft: true,
destination: '@WorldB',
},
{
amount: 329.4,
precision: 100,
reference: 'txn_002',
description: 'Refund processing',
currency: 'USD',
source: '@WorldB',
allow_overdraft: true,
destination: '@WorldA',
},
{
amount: 87.15,
precision: 100,
reference: 'txn_003',
description: 'Service charge',
currency: 'USD',
source: '@WorldA',
allow_overdraft: true,
destination: '@WorldB',
},
{
amount: 413.6,
precision: 100,
reference: 'txn_004',
description: 'Payment for goods',
currency: 'USD',
source: '@WorldB',
allow_overdraft: true,
destination: '@WorldA',
},
{
amount: 276.89,
precision: 100,
reference: 'txn_005',
description: 'Subscription fee',
currency: 'USD',
source: '@WorldA',
allow_overdraft: true,
destination: '@WorldB',
},
{
amount: 199.99,
precision: 100,
reference: 'txn_006',
description: 'Expense reimbursement',
currency: 'USD',
source: '@WorldB',
allow_overdraft: true,
destination: '@WorldA',
},
{
amount: 540.25,
precision: 100,
reference: 'txn_007',
description: 'Project funding',
currency: 'USD',
source: '@WorldA',
allow_overdraft: true,
destination: '@WorldB',
},
{
amount: 135.7,
precision: 100,
reference: 'txn_008',
description: 'Loan repayment',
currency: 'USD',
source: '@WorldB',
allow_overdraft: true,
destination: '@WorldA',
},
{
amount: 92.8,
precision: 100,
reference: 'txn_009',
description: 'Freelance payment',
currency: 'USD',
source: '@WorldA',
allow_overdraft: true,
destination: '@WorldB',
},
{
amount: 480.55,
precision: 100,
reference: 'txn_010',
description: 'Revenue share',
currency: 'USD',
source: '@WorldB',
allow_overdraft: true,
destination: '@WorldA',
},
],
});batch, _, _ := client.Transaction.CreateBulk(blnkgo.CreateBulkTransactionRequest{
Atomic: true,
Inflight: false,
RunAsync: false,
Transactions: []blnkgo.CreateTransactionRequest{
{
ParentTransaction: blnkgo.ParentTransaction{
Amount: 152.75,
Precision: 100,
Reference: "txn_001",
Description: "Invoice settlement",
Currency: "USD",
Source: "@WorldA",
Destination: "@WorldB",
},
AllowOverdraft: true,
},
{
ParentTransaction: blnkgo.ParentTransaction{
Amount: 329.40,
Precision: 100,
Reference: "txn_002",
Description: "Refund processing",
Currency: "USD",
Source: "@WorldB",
Destination: "@WorldA",
},
AllowOverdraft: true,
},
{
ParentTransaction: blnkgo.ParentTransaction{
Amount: 87.15,
Precision: 100,
Reference: "txn_003",
Description: "Service charge",
Currency: "USD",
Source: "@WorldA",
Destination: "@WorldB",
},
AllowOverdraft: true,
},
{
ParentTransaction: blnkgo.ParentTransaction{
Amount: 413.60,
Precision: 100,
Reference: "txn_004",
Description: "Payment for goods",
Currency: "USD",
Source: "@WorldB",
Destination: "@WorldA",
},
AllowOverdraft: true,
},
{
ParentTransaction: blnkgo.ParentTransaction{
Amount: 276.89,
Precision: 100,
Reference: "txn_005",
Description: "Subscription fee",
Currency: "USD",
Source: "@WorldA",
Destination: "@WorldB",
},
AllowOverdraft: true,
},
{
ParentTransaction: blnkgo.ParentTransaction{
Amount: 199.99,
Precision: 100,
Reference: "txn_006",
Description: "Expense reimbursement",
Currency: "USD",
Source: "@WorldB",
Destination: "@WorldA",
},
AllowOverdraft: true,
},
{
ParentTransaction: blnkgo.ParentTransaction{
Amount: 540.25,
Precision: 100,
Reference: "txn_007",
Description: "Project funding",
Currency: "USD",
Source: "@WorldA",
Destination: "@WorldB",
},
AllowOverdraft: true,
},
{
ParentTransaction: blnkgo.ParentTransaction{
Amount: 135.70,
Precision: 100,
Reference: "txn_008",
Description: "Loan repayment",
Currency: "USD",
Source: "@WorldB",
Destination: "@WorldA",
},
AllowOverdraft: true,
},
{
ParentTransaction: blnkgo.ParentTransaction{
Amount: 92.80,
Precision: 100,
Reference: "txn_009",
Description: "Freelance payment",
Currency: "USD",
Source: "@WorldA",
Destination: "@WorldB",
},
AllowOverdraft: true,
},
{
ParentTransaction: blnkgo.ParentTransaction{
Amount: 480.55,
Precision: 100,
Reference: "txn_010",
Description: "Revenue share",
Currency: "USD",
Source: "@WorldB",
Destination: "@WorldA",
},
AllowOverdraft: true,
},
},
})response = blnk.transactions.create_bulk({
"atomic": True,
"inflight": False,
"run_async": False,
"transactions": [
{
"amount": 152.75,
"precision": 100,
"reference": "txn_001",
"description": "Invoice settlement",
"currency": "USD",
"source": "@WorldA",
"allow_overdraft": True,
"destination": "@WorldB",
},
{
"amount": 329.40,
"precision": 100,
"reference": "txn_002",
"description": "Refund processing",
"currency": "USD",
"source": "@WorldB",
"allow_overdraft": True,
"destination": "@WorldA",
},
{
"amount": 87.15,
"precision": 100,
"reference": "txn_003",
"description": "Service charge",
"currency": "USD",
"source": "@WorldA",
"allow_overdraft": True,
"destination": "@WorldB",
},
{
"amount": 413.60,
"precision": 100,
"reference": "txn_004",
"description": "Payment for goods",
"currency": "USD",
"source": "@WorldB",
"allow_overdraft": True,
"destination": "@WorldA",
},
{
"amount": 276.89,
"precision": 100,
"reference": "txn_005",
"description": "Subscription fee",
"currency": "USD",
"source": "@WorldA",
"allow_overdraft": True,
"destination": "@WorldB",
},
{
"amount": 199.99,
"precision": 100,
"reference": "txn_006",
"description": "Expense reimbursement",
"currency": "USD",
"source": "@WorldB",
"allow_overdraft": True,
"destination": "@WorldA",
},
{
"amount": 540.25,
"precision": 100,
"reference": "txn_007",
"description": "Project funding",
"currency": "USD",
"source": "@WorldA",
"allow_overdraft": True,
"destination": "@WorldB",
},
{
"amount": 135.70,
"precision": 100,
"reference": "txn_008",
"description": "Loan repayment",
"currency": "USD",
"source": "@WorldB",
"allow_overdraft": True,
"destination": "@WorldA",
},
{
"amount": 92.80,
"precision": 100,
"reference": "txn_009",
"description": "Freelance payment",
"currency": "USD",
"source": "@WorldA",
"allow_overdraft": True,
"destination": "@WorldB",
},
{
"amount": 480.55,
"precision": 100,
"reference": "txn_010",
"description": "Revenue share",
"currency": "USD",
"source": "@WorldB",
"allow_overdraft": True,
"destination": "@WorldA",
},
],
})ApiResponse<JsonNode> response = blnk.transactions().createBulk(
BulkTransactions.create()
.atomic(true)
.inflight(false)
.runAsync(false)
.transactions(List.of(
CreateTransactions.create()
.amount(152.75)
.precision(100)
.reference("txn_001")
.description("Invoice settlement")
.currency("USD")
.source("@WorldA")
.allowOverdraft(true)
.destination("@WorldB"),
CreateTransactions.create()
.amount(329.40)
.precision(100)
.reference("txn_002")
.description("Refund processing")
.currency("USD")
.source("@WorldB")
.allowOverdraft(true)
.destination("@WorldA"),
CreateTransactions.create()
.amount(87.15)
.precision(100)
.reference("txn_003")
.description("Service charge")
.currency("USD")
.source("@WorldA")
.allowOverdraft(true)
.destination("@WorldB"),
CreateTransactions.create()
.amount(413.60)
.precision(100)
.reference("txn_004")
.description("Payment for goods")
.currency("USD")
.source("@WorldB")
.allowOverdraft(true)
.destination("@WorldA"),
CreateTransactions.create()
.amount(276.89)
.precision(100)
.reference("txn_005")
.description("Subscription fee")
.currency("USD")
.source("@WorldA")
.allowOverdraft(true)
.destination("@WorldB"),
CreateTransactions.create()
.amount(199.99)
.precision(100)
.reference("txn_006")
.description("Expense reimbursement")
.currency("USD")
.source("@WorldB")
.allowOverdraft(true)
.destination("@WorldA"),
CreateTransactions.create()
.amount(540.25)
.precision(100)
.reference("txn_007")
.description("Project funding")
.currency("USD")
.source("@WorldA")
.allowOverdraft(true)
.destination("@WorldB"),
CreateTransactions.create()
.amount(135.70)
.precision(100)
.reference("txn_008")
.description("Loan repayment")
.currency("USD")
.source("@WorldB")
.allowOverdraft(true)
.destination("@WorldA"),
CreateTransactions.create()
.amount(92.80)
.precision(100)
.reference("txn_009")
.description("Freelance payment")
.currency("USD")
.source("@WorldA")
.allowOverdraft(true)
.destination("@WorldB"),
CreateTransactions.create()
.amount(480.55)
.precision(100)
.reference("txn_010")
.description("Revenue share")
.currency("USD")
.source("@WorldB")
.allowOverdraft(true)
.destination("@WorldA")
))
);{
"batch_id": "bulk_4192d961-5b0e-46ca-bf2f-9386763057f8",
"status": "applied",
"transaction_count": 10
}Prepare the external file
Download the sample CSV. The rows already use the fields on External data.
Upload the file
Call Upload external records. Keep the upload_id from the response.
curl -X POST "http://localhost:5001/reconciliation/upload" \
-H "X-blnk-key: <api-key>" \
-F "file=@recon-example-external-source.csv" \
-F "source=Stripe"const response = await blnk.Reconciliation.upload(
'recon-example-external-source.csv',
'Stripe',
);file, _ := os.Open("recon-example-external-source.csv")
result, _, _ := client.Reconciliation.Upload("Stripe", file, file.Name())response = blnk.reconciliation.upload("recon-example-external-source.csv", "Stripe")ApiResponse<JsonNode> response = blnk.reconciliation().upload(
"recon-example-external-source.csv",
"Stripe"
);{
"upload_id": "upload_0cd4a87d-544c-4b7e-9232-f36e79631c32",
"record_count": 10,
"source": "Stripe"
}Create a matching rule
This rule matches when amount, currency, and reference are all equal. Every criterion has to match.
Call Create matching rule and keep the rule_id.
curl -X POST "http://localhost:5001/reconciliation/matching-rules" \
-H "X-blnk-key: <api-key>" \
-H "Content-Type: application/json" \
-d '{
"name": "Basic matcher",
"description": "Matches transactions by amount and reference",
"criteria": [
{
"field": "amount",
"operator": "equals"
},
{
"field": "currency",
"operator": "equals"
},
{
"field": "reference",
"operator": "equals"
}
]
}'const response = await blnk.Reconciliation.createMatchingRule({
name: 'Basic matcher',
description: 'Matches transactions by amount and reference',
criteria: [
{
field: 'amount',
operator: 'equals',
},
{
field: 'currency',
operator: 'equals',
},
{
field: 'reference',
operator: 'equals',
},
],
});rule, _, _ := client.Reconciliation.CreateMatchingRule(blnkgo.Matcher{
Name: "Basic matcher",
Description: "Matches transactions by amount and reference",
Criteria: []blnkgo.Criteria{
{
Field: blnkgo.CriteriaFieldAmount,
Operator: blnkgo.ReconciliationOperatorEquals,
},
{
Field: blnkgo.CriteriaFieldCurrency,
Operator: blnkgo.ReconciliationOperatorEquals,
},
{
Field: blnkgo.CriteriaFieldReference,
Operator: blnkgo.ReconciliationOperatorEquals,
},
},
})response = blnk.reconciliation.create_matching_rule({
"name": "Basic matcher",
"description": "Matches transactions by amount and reference",
"criteria": [
{
"field": "amount",
"operator": "equals",
},
{
"field": "currency",
"operator": "equals",
},
{
"field": "reference",
"operator": "equals",
},
],
})ApiResponse<JsonNode> response = blnk.reconciliation().createMatchingRule(
Matcher.create()
.name("Basic matcher")
.description("Matches transactions by amount and reference")
.criteria(List.of(
Criteria.create()
.field("amount")
.operator("equals"),
Criteria.create()
.field("currency")
.operator("equals"),
Criteria.create()
.field("reference")
.operator("equals")
))
);{
"rule_id": "rule_3d5ae6d4-6722-40c5-ac4b-0bd66ab7d363",
"name": "Basic matcher",
"description": "Matches transactions by amount and reference",
"criteria": [
{
"field": "amount",
"operator": "equals",
"value": "",
"pattern": "",
"allowable_drift": 0
},
{
"field": "currency",
"operator": "equals",
"value": "",
"pattern": "",
"allowable_drift": 0
},
{
"field": "reference",
"operator": "equals",
"value": "",
"pattern": "",
"allowable_drift": 0
}
],
"created_at": "2025-03-17T08:31:24.97610651Z",
"updated_at": "2025-03-17T08:31:24.976106635Z"
}Start the run
Start a batch reconciliation with one_to_one. Do not send grouping_criteria. Use the upload id and rule id from the steps above.
curl -X POST "http://localhost:5001/reconciliation/start" \
-H "X-blnk-key: <api-key>" \
-H "Content-Type: application/json" \
-d '{
"upload_id": "upload_0cd4a87d-544c-4b7e-9232-f36e79631c32",
"strategy": "one_to_one",
"matching_rule_ids": [
"rule_3d5ae6d4-6722-40c5-ac4b-0bd66ab7d363"
]
}'const response = await blnk.Reconciliation.run({
upload_id: 'upload_0cd4a87d-544c-4b7e-9232-f36e79631c32',
strategy: 'one_to_one',
matching_rule_ids: [
'rule_3d5ae6d4-6722-40c5-ac4b-0bd66ab7d363',
],
});result, _, _ := client.Reconciliation.Run(blnkgo.RunReconData{
UploadID: "upload_0cd4a87d-544c-4b7e-9232-f36e79631c32",
Strategy: blnkgo.ReconciliationStrategyOneToOne,
MatchingRuleIDs: []string{
"rule_3d5ae6d4-6722-40c5-ac4b-0bd66ab7d363",
},
})response = blnk.reconciliation.run({
"upload_id": "upload_0cd4a87d-544c-4b7e-9232-f36e79631c32",
"strategy": "one_to_one",
"matching_rule_ids": [
"rule_3d5ae6d4-6722-40c5-ac4b-0bd66ab7d363",
],
})ApiResponse<JsonNode> response = blnk.reconciliation().run(
RunReconData.create()
.uploadId("upload_0cd4a87d-544c-4b7e-9232-f36e79631c32")
.strategy("one_to_one")
.matchingRuleIds(List.of(
"rule_3d5ae6d4-6722-40c5-ac4b-0bd66ab7d363"
))
);{
"reconciliation_id": "recon_f1df3e68-fd8d-4566-8670-891c3c1e7d58"
}Read the result
Call Get reconciliation with the id from the start response. This sample finished with 2 matches and 8 unmatched rows.
curl -X GET "http://localhost:5001/reconciliation/recon_f1df3e68-fd8d-4566-8670-891c3c1e7d58" \
-H "X-blnk-key: <api-key>"const response = await blnk.Reconciliation.get(
'recon_f1df3e68-fd8d-4566-8670-891c3c1e7d58',
);recon, _, _ := client.Reconciliation.Get(
"recon_f1df3e68-fd8d-4566-8670-891c3c1e7d58",
)response = blnk.reconciliation.get(
"recon_f1df3e68-fd8d-4566-8670-891c3c1e7d58",
)ApiResponse<JsonNode> response = blnk.reconciliation().get(
"recon_f1df3e68-fd8d-4566-8670-891c3c1e7d58"
);{
"reconciliation_id": "recon_f1df3e68-fd8d-4566-8670-891c3c1e7d58",
"upload_id": "upload_0cd4a87d-544c-4b7e-9232-f36e79631c32",
"status": "completed",
"matched_transactions": 2,
"unmatched_transactions": 8,
"started_at": "2025-03-17T08:32:24.005476Z",
"completed_at": "2025-03-17T08:32:24.062136Z"
}
| Field | Description |
|---|---|
matched_transactions | How many external records matched. |
unmatched_transactions | How many external records did not match. |