Transactions
Commit inflight transactions
Apply one hold, many holds, or every leg in a split or batch.
After you create an inflight transaction, commit it when the main balance should change.
Commit clears the inflight balance fields and moves the reserved amount into the main balances.

Commit one transaction
Commit the full amount
Call Update inflight with the inflight transaction id and "status": "commit".
PUT /transactions/inflight/{transaction_id}curl -X PUT "http://YOUR_BLNK_INSTANCE_URL/transactions/inflight/{transaction_id}" \
-H "X-blnk-key: <api-key>" \
-H "Content-Type: application/json" \
-d '{
"status": "commit"
}'const response = await blnk.Transactions.updateStatus(
'{transaction_id}',
{
status: 'commit',
},
);transaction, _, _ := client.Transaction.Update(
"{transaction_id}",
blnkgo.UpdateStatus{
Status: blnkgo.InflightStatusCommit,
},
)response = blnk.transactions.update_status(
"{transaction_id}",
{
"status": "commit",
},
)ApiResponse<JsonNode> response = blnk.transactions().updateStatus(
"{transaction_id}",
UpdateTransactionStatus.create()
.status("commit"));{
"transaction_id": "txn_6164573b-6cc8-45a4-ad2e-7b4ba6a60f7d",
"status": "INFLIGHT",
"queued": true
}queued: true means the commit is waiting on a worker, not that the main balance has changed.
With skip_queue: true, the same call returns the APPLIED child and sets parent_transaction to the inflight id.
Continuing from the earlier example, a full commit of the $100 hold looks like this:
balance_id | Main balance | Inflight balance | Inflight credit | Inflight debit |
|---|---|---|---|---|
balance_A | 100 | 0 | 0 | 0 |
balance_B | 100 | 0 | 0 | 0 |
Commit part of the amount
Set precise_amount to the amount you want to commit, in its smallest unit. The rest stays INFLIGHT.
You can commit more than once. The total cannot exceed the original inflight amount.
A $100 hold can take three $30 commits ($90). A fourth $30 commit fails because $120 is more than the original $100.
curl -X PUT "http://YOUR_BLNK_INSTANCE_URL/transactions/inflight/{transaction_id}" \
-H "X-blnk-key: <api-key>" \
-H "Content-Type: application/json" \
-d '{
"status": "commit",
"precise_amount": 4000
}'const response = await blnk.Transactions.updateStatus(
'{transaction_id}',
{
status: 'commit',
precise_amount: 4000,
},
);transaction, _, _ := client.Transaction.Update(
"{transaction_id}",
blnkgo.UpdateStatus{
Status: blnkgo.InflightStatusCommit,
PreciseAmount: big.NewInt(4000),
},
)response = blnk.transactions.update_status(
"{transaction_id}",
{
"status": "commit",
"precise_amount": 4000,
},
)ApiResponse<JsonNode> response = blnk.transactions().updateStatus(
"{transaction_id}",
UpdateTransactionStatus.create()
.status("commit")
.preciseAmount(4000));A partial commit of $40 from the $100 hold leaves the remaining $60 inflight:
balance_id | Main balance | Inflight balance | Inflight credit | Inflight debit |
|---|---|---|---|---|
balance_A | 160 | -60 | 0 | 60 |
balance_B | 40 | 60 | 60 | 0 |
Void releases whatever is still held. It does not reverse amount you already committed.
Commit the full amount
Open the inflight transaction. Commit completes it.

Select Commit transaction, or press C. Leave Amount to commit empty, then confirm.

A new linked transaction is created with status APPLIED.
Commit part of the amount
Enter the amount in Amount to commit, then confirm. The rest stays inflight.
Leave Amount to commit empty on the last commit. That applies whatever is still held.
Commit multiple inflights
Commit the holds
Use Bulk commit inflight for holds you created one by one. Each bulk commit request accepts at most 100 items.
POST /transactions/inflight/bulk/commitcurl -X POST "http://YOUR_BLNK_INSTANCE_URL/transactions/inflight/bulk/commit" \
-H "X-blnk-key: <api-key>" \
-H "Content-Type: application/json" \
-d '{
"transactions": [
{
"transaction_id": "txn_f482a1b3-6c2d-4e89-a17b-3d5e8f2a1c94"
},
{
"transaction_id": "txn_c5d9e2a1-7b4f-4a3c-9e8d-1f6a2b4c8d30",
"precise_amount": 4000
}
]
}'const response = await blnk.Transactions.bulkCommitInflight({
transactions: [
{
transaction_id: 'txn_f482a1b3-6c2d-4e89-a17b-3d5e8f2a1c94',
},
{
transaction_id: 'txn_c5d9e2a1-7b4f-4a3c-9e8d-1f6a2b4c8d30',
precise_amount: 4000,
},
],
});result, _, _ := client.Transaction.BulkCommitInflight(blnkgo.BulkCommitInflightRequest{
Transactions: []blnkgo.BulkCommitInflightItem{
{
TransactionID: "txn_f482a1b3-6c2d-4e89-a17b-3d5e8f2a1c94",
},
{
TransactionID: "txn_c5d9e2a1-7b4f-4a3c-9e8d-1f6a2b4c8d30",
PreciseAmount: big.NewInt(4000),
},
},
})response = blnk.transactions.bulk_commit_inflight({
"transactions": [
{
"transaction_id": "txn_f482a1b3-6c2d-4e89-a17b-3d5e8f2a1c94",
},
{
"transaction_id": "txn_c5d9e2a1-7b4f-4a3c-9e8d-1f6a2b4c8d30",
"precise_amount": 4000,
},
],
})ApiResponse<JsonNode> response = blnk.transactions().bulkCommitInflight(
BulkCommitInflightRequest.create()
.transactions(List.of(
BulkCommitInflightItem.create()
.transactionId("txn_f482a1b3-6c2d-4e89-a17b-3d5e8f2a1c94"),
BulkCommitInflightItem.create()
.transactionId("txn_c5d9e2a1-7b4f-4a3c-9e8d-1f6a2b4c8d30")
.preciseAmount(4000)
)));Read the result
One failed item does not block the rest.
| Status | Code | Meaning |
|---|---|---|
queued | QUEUED | New commit job added. |
queued | ALREADY_QUEUED | Already queued. The duplicate is skipped. |
{
"succeeded": 2,
"failed": 0,
"results": [
{
"transaction_id": "txn_f482a1b3-6c2d-4e89-a17b-3d5e8f2a1c94",
"status": "queued",
"code": "QUEUED"
},
{
"transaction_id": "txn_c5d9e2a1-7b4f-4a3c-9e8d-1f6a2b4c8d30",
"status": "queued",
"code": "ALREADY_QUEUED"
}
]
}QUEUED and ALREADY_QUEUED both count toward succeeded. Set skip_queue: true to process each item in the request. Those results use succeeded or failed instead of queued.
Commit a split or a bulk batch
Choose the parent id
A split uses the root transaction_id. A bulk batch uses batch_id. That id commits every pending leg.
Commit the split or batch
Call Update single inflight with that id and "status": "commit". Do not send that id to Bulk commit inflight.
PUT /transactions/inflight/{parent_id}curl -X PUT "http://YOUR_BLNK_INSTANCE_URL/transactions/inflight/{parent_id}" \
-H "X-blnk-key: <api-key>" \
-H "Content-Type: application/json" \
-d '{
"status": "commit"
}'const response = await blnk.Transactions.updateStatus(
'{parent_id}',
{
status: 'commit',
},
);transaction, _, _ := client.Transaction.Update(
"{parent_id}",
blnkgo.UpdateStatus{
Status: blnkgo.InflightStatusCommit,
},
)response = blnk.transactions.update_status(
"{parent_id}",
{
"status": "commit",
},
)ApiResponse<JsonNode> response = blnk.transactions().updateStatus(
"{parent_id}",
UpdateTransactionStatus.create()
.status("commit"));{
"transaction_id": "txn_0b59f6e6-6c4a-4efa-915c-526f77ef61ab",
"status": "INFLIGHT",
"queued": true
}On the default queue, the response stays INFLIGHT with queued: true. Every leg and its later APPLIED child shares meta_data.QUEUED_PARENT_TRANSACTION.
With skip_queue: true, the response reflects the first leg processed. Each leg’s APPLIED child points at that leg through parent_transaction, so check each leg on its own.
Verify the outcome
You can confirm a commit or a void in two ways. Listen for the event, or filter the child transactions in the database.
Listen for the event
Blnk sends transaction.applied when a commit finishes, and transaction.void when a void finishes.
On the default queue, match meta_data.QUEUED_PARENT_TRANSACTION on the child to the inflight id. If the request skipped the queue, match parent_transaction to that id.
{
"event": "transaction.applied",
"data": {
"transaction_id": "txn_e0f5ab98-bb87-4b09-aefe-839ddb11598b",
"parent_transaction": "txn_6164573b-6cc8-45a4-ad2e-7b4ba6a60f7d",
"precise_amount": 20000,
"amount": 200,
"precision": 100,
"source": "bln_7f91a1ae-6073-4b7a-952c-23abf94a6634",
"destination": "bln_59b83b9c-842c-427f-91eb-43cdeaf5c01a",
"reference": "ref_001adcfgf_q",
"currency": "GBP",
"description": "For vacation",
"status": "APPLIED",
"inflight": false,
"created_at": "2025-02-23T09:43:49.623494+01:00",
"meta_data": {
"QUEUED_PARENT_TRANSACTION": "txn_6164573b-6cc8-45a4-ad2e-7b4ba6a60f7d",
"inflight": true
}
}
}{
"event": "transaction.void",
"data": {
"transaction_id": "txn_c3d4e5f6-a7b8-9012-cdef-345678901234",
"parent_transaction": "txn_6164573b-6cc8-45a4-ad2e-7b4ba6a60f7d",
"precise_amount": 6000,
"amount": 60,
"precision": 100,
"source": "bln_7f91a1ae-6073-4b7a-952c-23abf94a6634",
"destination": "bln_59b83b9c-842c-427f-91eb-43cdeaf5c01a",
"reference": "ref_e7d61840-ecf7-45c1-a0b2-41687c7691f7_q",
"currency": "GBP",
"description": "For vacation",
"status": "VOID",
"inflight": false,
"created_at": "2025-02-23T09:45:03.332221+01:00",
"meta_data": {
"QUEUED_PARENT_TRANSACTION": "txn_6164573b-6cc8-45a4-ad2e-7b4ba6a60f7d",
"inflight": true
}
}
}Filter the database
Use the Filter API to read the children from the database. A finished commit has status APPLIED. A finished void has status VOID.
Filter meta_data.QUEUED_PARENT_TRANSACTION for the inflight id, and keep children whose status is APPLIED or VOID. Each child’s parent_transaction points at the queued commit or void, so the shared key is QUEUED_PARENT_TRANSACTION.
curl -X POST "http://YOUR_BLNK_INSTANCE_URL/transactions/filter" \
-H "X-blnk-key: <api-key>" \
-H "Content-Type: application/json" \
-d '{
"filters": [
{
"field": "meta_data.QUEUED_PARENT_TRANSACTION",
"operator": "eq",
"value": "<inflight_transaction_id>"
},
{
"field": "status",
"operator": "in",
"values": ["APPLIED", "VOID"]
}
]
}'const response = await blnk.Search.filter(
{
filters: [
{
field: 'meta_data.QUEUED_PARENT_TRANSACTION',
operator: 'eq',
value: '<inflight_transaction_id>',
},
{
field: 'status',
operator: 'in',
values: ['APPLIED', 'VOID'],
},
],
},
'transactions',
);results, _, _ := client.Transaction.Filter(blnkgo.FilterParams{
Filters: []blnkgo.Filter{
{
Field: "meta_data.QUEUED_PARENT_TRANSACTION",
Operator: blnkgo.OpEqual,
Value: "<inflight_transaction_id>",
},
{
Field: "status",
Operator: blnkgo.OpIn,
Values: []interface{}{"APPLIED", "VOID"},
},
},
})response = blnk.search.filter(
{
"filters": [
{
"field": "meta_data.QUEUED_PARENT_TRANSACTION",
"operator": "eq",
"value": "<inflight_transaction_id>",
},
{
"field": "status",
"operator": "in",
"values": ["APPLIED", "VOID"],
},
],
},
"transactions",
)ApiResponse<JsonNode> response = blnk.search().filter(
FilterParams.create()
.filters(List.of(
FilterCondition.create()
.field("meta_data.QUEUED_PARENT_TRANSACTION")
.operator("eq")
.value("<inflight_transaction_id>"),
FilterCondition.create()
.field("status")
.operator("in")
.values(List.of("APPLIED", "VOID"))
)),
"transactions");{
"data": [
{
"transaction_id": "txn_b2c3d4e5-f6a7-8901-bcde-f23456789012",
"parent_transaction": "txn_d8f4a291-3e7c-41b6-a05d-9c2e71b48f6a",
"status": "APPLIED",
"meta_data": {
"QUEUED_PARENT_TRANSACTION": "txn_6164573b-6cc8-45a4-ad2e-7b4ba6a60f7d"
}
},
{
"transaction_id": "txn_c3d4e5f6-a7b8-9012-cdef-345678901234",
"parent_transaction": "txn_4a9c0e75-1b62-483f-8d31-7f6a25e903d4",
"status": "VOID",
"meta_data": {
"QUEUED_PARENT_TRANSACTION": "txn_6164573b-6cc8-45a4-ad2e-7b4ba6a60f7d"
}
}
]
}Filter parent_transaction for the inflight id, and keep children whose status is APPLIED or VOID. The child links straight to that inflight transaction.
curl -X POST "http://YOUR_BLNK_INSTANCE_URL/transactions/filter" \
-H "X-blnk-key: <api-key>" \
-H "Content-Type: application/json" \
-d '{
"filters": [
{
"field": "parent_transaction",
"operator": "eq",
"value": "<inflight_transaction_id>"
},
{
"field": "status",
"operator": "in",
"values": ["APPLIED", "VOID"]
}
]
}'const response = await blnk.Search.filter(
{
filters: [
{
field: 'parent_transaction',
operator: 'eq',
value: '<inflight_transaction_id>',
},
{
field: 'status',
operator: 'in',
values: ['APPLIED', 'VOID'],
},
],
},
'transactions',
);results, _, _ := client.Transaction.Filter(blnkgo.FilterParams{
Filters: []blnkgo.Filter{
{
Field: "parent_transaction",
Operator: blnkgo.OpEqual,
Value: "<inflight_transaction_id>",
},
{
Field: "status",
Operator: blnkgo.OpIn,
Values: []interface{}{"APPLIED", "VOID"},
},
},
})response = blnk.search.filter(
{
"filters": [
{
"field": "parent_transaction",
"operator": "eq",
"value": "<inflight_transaction_id>",
},
{
"field": "status",
"operator": "in",
"values": ["APPLIED", "VOID"],
},
],
},
"transactions",
)ApiResponse<JsonNode> response = blnk.search().filter(
FilterParams.create()
.filters(List.of(
FilterCondition.create()
.field("parent_transaction")
.operator("eq")
.value("<inflight_transaction_id>"),
FilterCondition.create()
.field("status")
.operator("in")
.values(List.of("APPLIED", "VOID"))
)),
"transactions");{
"data": [
{
"transaction_id": "txn_b2c3d4e5-f6a7-8901-bcde-f23456789012",
"parent_transaction": "txn_6164573b-6cc8-45a4-ad2e-7b4ba6a60f7d",
"status": "APPLIED",
"meta_data": {
"inflight": true
}
},
{
"transaction_id": "txn_c3d4e5f6-a7b8-9012-cdef-345678901234",
"parent_transaction": "txn_6164573b-6cc8-45a4-ad2e-7b4ba6a60f7d",
"status": "VOID",
"meta_data": {
"inflight": true
}
}
]
}Schedule a commit
Set inflight_commit_date when you create the hold. Blnk reserves the funds immediately and commits them at that time.
Use this when funds need to be held now and released at a known future time, such as a hotel deposit that settles on check-in.
curl -X POST "http://YOUR_BLNK_INSTANCE_URL/transactions" \
-H "X-blnk-key: <api-key>" \
-H "Content-Type: application/json" \
-d '{
"precise_amount": 10000,
"precision": 100,
"reference": "ref_001adcfgf",
"currency": "USD",
"source": "bln_28edb3e5-c168-4127-a1c4-16274e7a28d3",
"destination": "bln_ebcd230f-6265-4d4a-a4ca-45974c47f746",
"description": "For vacation",
"inflight": true,
"inflight_commit_date": "2024-12-21T01:36:46+01:00"
}'const response = await blnk.Transactions.create({
precise_amount: 10000,
precision: 100,
reference: 'ref_001adcfgf',
currency: 'USD',
source: 'bln_28edb3e5-c168-4127-a1c4-16274e7a28d3',
destination: 'bln_ebcd230f-6265-4d4a-a4ca-45974c47f746',
description: 'For vacation',
inflight: true,
inflight_commit_date: '2024-12-21T01:36:46+01:00',
});transaction, _, _ := client.Transaction.Create(blnkgo.CreateTransactionRequest{
ParentTransaction: blnkgo.ParentTransaction{
PreciseAmount: big.NewInt(10000),
Precision: 100,
Reference: "ref_001adcfgf",
Currency: "USD",
Source: "bln_28edb3e5-c168-4127-a1c4-16274e7a28d3",
Destination: "bln_ebcd230f-6265-4d4a-a4ca-45974c47f746",
Description: "For vacation",
},
Inflight: true,
InflightCommitDate: "2024-12-21T01:36:46+01:00",
})response = blnk.transactions.create({
"precise_amount": 10000,
"precision": 100,
"reference": "ref_001adcfgf",
"currency": "USD",
"source": "bln_28edb3e5-c168-4127-a1c4-16274e7a28d3",
"destination": "bln_ebcd230f-6265-4d4a-a4ca-45974c47f746",
"description": "For vacation",
"inflight": True,
"inflight_commit_date": "2024-12-21T01:36:46+01:00",
})ApiResponse<JsonNode> response = blnk.transactions().create(
CreateTransactions.create()
.preciseAmount(10000)
.precision(100)
.reference("ref_001adcfgf")
.currency("USD")
.source("bln_28edb3e5-c168-4127-a1c4-16274e7a28d3")
.destination("bln_ebcd230f-6265-4d4a-a4ca-45974c47f746")
.description("For vacation")
.inflight(true)
.inflightCommitDate("2024-12-21T01:36:46+01:00"));{
"transaction_id": "txn_6164573b-6cc8-45a4-ad2e-7b4ba6a60f7d",
"status": "INFLIGHT",
"inflight": true,
"inflight_commit_date": "2024-12-21T01:36:46+01:00"
}
If you also set inflight_expiry_date, the commit time has to be earlier than the expiry. Otherwise, Blnk voids the hold before the scheduled commit runs. See Schedule inflight expiry.
Error handling
Update inflight returns 400, 404, and 409 when a commit fails validation or conflicts with the current state.
On the default queue, Blnk rejects a second commit or void before enqueueing another job. With skip_queue: true, Blnk validates in the request and returns the error immediately.
| Code | When it happens |
|---|---|
GEN_CONFLICT | A commit or void is already queued for this inflight transaction. |
TXN_COMMIT_AMOUNT_EXCEEDED | The partial commit exceeds the remaining inflight amount. |
TXN_ALREADY_VOIDED | You try to commit a voided inflight transaction. |
TXN_NOT_INFLIGHT | The transaction is not INFLIGHT. |
TXN_INVALID_STATUS_ACTION | status is not commit or void. |
TXN_NOT_FOUND | The transaction id does not exist, or it is not the split or batch parent. |
{
"error": "a commit or void is already queued for this transaction",
"error_detail": {
"code": "GEN_CONFLICT",
"message": "a commit or void is already queued for this transaction"
}
}
To resolve the error:
| Code | What to do |
|---|---|
GEN_CONFLICT | Wait for the queued job to finish, or verify the outcome before sending another request. |
TXN_COMMIT_AMOUNT_EXCEEDED | Lower precise_amount to the remaining inflight amount, or commit the full remainder. |
TXN_ALREADY_VOIDED | Treat the hold as cancelled. Do not commit it. |
TXN_NOT_INFLIGHT | Use the original inflight id, not an APPLIED or VOID child. |
TXN_INVALID_STATUS_ACTION | Set status to commit. |
TXN_NOT_FOUND | For a split or batch, use the parent id from create, not a leg or child id. |
Bulk commit inflight returns 400 before any item is processed when the body is invalid. Per-item failures return 200 with failed entries in results. One failed item does not block the batch.
| Code | When it happens |
|---|---|
TXN_BULK_EMPTY | transactions is missing, empty, or the wrong shape. |
TXN_BULK_LIMIT_EXCEEDED | More than 100 items in one request. |
With skip_queue: true, a failed item can return NOT_FOUND, ALREADY_COMMITTED, ALREADY_VOIDED, NOT_INFLIGHT, INVALID_AMOUNT, LOCKED, or INTERNAL_ERROR. See API error codes.