Start here
0.10.5 Migration Guide
Decide whether bulk create should stay synchronous before you upgrade to Blnk v0.10.5.
This migration guide covers the breaking change introduced in Blnk v0.10.5 for bulk transactions. Bulk create now uses the queue by default instead of processing every item synchronously in the request. If you are upgrading from v0.10.4 or earlier and your app expects balances or final statuses to update before the bulk create response returns, review this guide before you upgrade.
Recommended upgrade
If you run 0.10.5 or later on the queued bulk path, upgrade to Blnk Core 0.15.0 or later. From 0.15.0, Core migrations add expression indexes on meta_data->>'QUEUED_PARENT_TRANSACTION' and related queue hot paths. Without those indexes, commit, refund, and parent lookups can fall back to sequential scans and drain the queue slowly under load.
Prefer upgrading over staying on 0.10.5 – 0.14.x with a hand-applied index. If you cannot upgrade yet, create the index manually on your Postgres database:
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_transactions_queued_parent
ON blnk.transactions ((meta_data->>'QUEUED_PARENT_TRANSACTION'));
Core 0.15.0 applies an equivalent index as idx_txn_meta_queued_parent (partial, where the key is present) plus related queue indexes. After you upgrade, you do not need to keep a separate hand-created index unless your operator process requires it.
Breaking changes summary
- From: Bulk create always processed items synchronously (
skip_queueeffectivelytrue). - To: Bulk create defaults to
skip_queue: falseand enqueues each item. - Impact: A successful bulk response no longer guarantees that every child transaction is already
APPLIEDorINFLIGHTon balances. Parent linking and duplicate-reference behaviour also follow the queued path unless you opt out.
What changed
- Default queueing: Bulk create now respects
skip_queueand defaults it tofalse. Before 0.10.5, Blnk forced synchronous processing inside the batch. - Response meaning: On the default path,
status: "applied"means the batch was successfully submitted, not that every child has already moved balances. - Parent linking: With
skip_queue: false, children storebatch_idinmeta_data.QUEUED_PARENT_TRANSACTION. Withskip_queue: true, children setparent_transactiontobatch_id. - Duplicate references: On the queued path, duplicate references are deduplicated silently and the batch can still return
201. Onskip_queue: true, duplicates fail the batch with409.
See Bulk transactions for current behaviour.
Who is affected?
Review this change if your integration:
- Reads balances or child transaction statuses immediately after bulk create
- Treats bulk
status: "applied"as proof that every item is final - Looks up batch children only by
parent_transaction - Relies on synchronous
409failures for duplicate references inside a bulk request
If none of these apply, you can upgrade without changing your bulk requests.
Migration options
Choose one path based on what your next step needs.
| Need | What to do |
|---|---|
| Keep pre-0.10.5 synchronous behaviour | Send "skip_queue": true on every bulk create |
| Adopt the new default queue path | Omit skip_queue or set "skip_queue": false, then confirm child outcomes asynchronously |
Option 1: Keep synchronous processing
Add "skip_queue": true to restore the previous inline behaviour. Use this when the next step in your app needs the ledger outcome before the HTTP call returns (for example, show an updated balance, fail the request with the batch, or chain another post that depends on these balances).
curl -X POST "http://YOUR_BLNK_INSTANCE_URL/transactions/bulk" \
-H "X-blnk-key: <api-key>" \
-H "Content-Type: application/json" \
-d '{
"atomic": true,
"inflight": false,
"run_async": false,
"skip_queue": true,
"transactions": [
{
"amount": 1000,
"precision": 100,
"reference": "ref_f482a1b3-6c2d-4e89-a17b-3d5e8f2a1c94",
"currency": "USD",
"source": "@World",
"destination": "bln_ebcd1a29-8673-4d31-b410-010add942bec",
"description": "Payroll credit",
"allow_overdraft": true
},
{
"amount": 500,
"precision": 100,
"reference": "ref_c5d9e2a1-7b4f-4a3c-9e8d-1f6a2b4c8d30",
"currency": "USD",
"source": "bln_ebcd1a29-8673-4d31-b410-010add942bec",
"destination": "bln_7b8a2c1d-4e5f-6a7b-8c9d-0e1f2a3b4c5d",
"description": "Payroll split"
}
]
}'const response = await blnk.Transactions.createBulk({
atomic: true,
inflight: false,
run_async: false,
skip_queue: true,
transactions: [
{
amount: 1000,
precision: 100,
reference: 'ref_f482a1b3-6c2d-4e89-a17b-3d5e8f2a1c94',
currency: 'USD',
source: '@World',
destination: 'bln_ebcd1a29-8673-4d31-b410-010add942bec',
description: 'Payroll credit',
allow_overdraft: true,
},
{
amount: 500,
precision: 100,
reference: 'ref_c5d9e2a1-7b4f-4a3c-9e8d-1f6a2b4c8d30',
currency: 'USD',
source: 'bln_ebcd1a29-8673-4d31-b410-010add942bec',
destination: 'bln_7b8a2c1d-4e5f-6a7b-8c9d-0e1f2a3b4c5d',
description: 'Payroll split',
},
],
});result, _, _ := client.Transaction.CreateBulk(blnkgo.CreateBulkTransactionRequest{
Atomic: true,
Inflight: false,
RunAsync: false,
SkipQueue: true,
Transactions: []blnkgo.CreateTransactionRequest{
{
Amount: 1000,
Precision: 100,
Reference: "ref_f482a1b3-6c2d-4e89-a17b-3d5e8f2a1c94",
Currency: "USD",
Source: "@World",
Destination: "bln_ebcd1a29-8673-4d31-b410-010add942bec",
Description: "Payroll credit",
AllowOverdraft: true,
},
{
Amount: 500,
Precision: 100,
Reference: "ref_c5d9e2a1-7b4f-4a3c-9e8d-1f6a2b4c8d30",
Currency: "USD",
Source: "bln_ebcd1a29-8673-4d31-b410-010add942bec",
Destination: "bln_7b8a2c1d-4e5f-6a7b-8c9d-0e1f2a3b4c5d",
Description: "Payroll split",
},
},
})With skip_queue: true:
- Child statuses and balances update in the same request when
run_asyncisfalse. - Look up children with
parent_transaction = batch_id. - Duplicate references fail the batch with
409.
Option 2: Adopt the queued default
Omit skip_queue or set "skip_queue": false. Then update your confirmation path:
- Save
batch_idfrom the create response. - Do not treat
status: "applied"as final ledger success for every child. - Confirm child outcomes by filtering on
meta_data.QUEUED_PARENT_TRANSACTION, or wait for webhook events.
{
"batch_id": "bulk_c62f200b-905f-4983-a349-cadd279234aa",
"status": "applied",
"transaction_count": 2
}
Migration checklist
- Prefer upgrading to 0.15.0 or later so queue parent indexes are applied by migration.
- If you must stay below 0.15.0 for now, create
idx_transactions_queued_parentmanually (see Recommended upgrade). - Decide per bulk call whether you need sync (
skip_queue: true) or queue (skip_queue: false). - Update any code that assumes balances change, or that an external payout is safe, before the bulk create response returns.
- Confirm child outcomes with webhooks or by filtering on
meta_data.QUEUED_PARENT_TRANSACTIONbefore you call external providers or release funds. - Update batch child lookups to use
meta_data.QUEUED_PARENT_TRANSACTIONon the default path, orparent_transactionwhen you setskip_queue: true. - Revisit duplicate-reference handling if you previously relied on synchronous
409failures. - For large batches, prefer
run_async: trueand handle bulk webhooks.