Build a Balanced ICL Deposit File¶
GIB only processes balanced forward files. This guide explains what that means and shows how to add the deposit ticket that balances each bundle, using the JSON form of an ICL file.
All fields of the JSON format are in the ICL API Reference. The rules for deposit tickets are on the Check (ICL) page.
What "balanced" means¶
Every check in a deposit file is a debit: it asks the bank the check is drawn on to pay. Something has to say where that money goes. In a balanced file, that is the deposit ticket: one credit record per bundle, naming the account at GIB that receives the funds.
A bundle is balanced when its deposit ticket equals the sum of its checks:
Deposit ticket credit your account at GIB $300.00
Check 1 debit drawn on another bank $100.00
Check 2 debit drawn on another bank $200.00
-------
Credits $300.00 = Debits $300.00 balanced
An unbalanced file carries only the checks, with nothing telling GIB's core which account to credit. GIB requires a balanced file.
The deposit ticket is not a special record type. It is a Check Detail (Type 25) record, like the checks, placed first in the bundle. That is why it counts as an item in the bundle, cash letter, and file totals.
Step 1 - Gather required data¶
Most integrators get the check records from their image-capture or RDC vendor. You need:
- The bundle's check records, as your capture system produced them, with images and a Check Detail Addendum A on each.
ACCOUNT_NUMBER- The account at GIB that receives the deposit.TRAN_CODE- Your program's deposit tran code. GIB gives you this at onboarding.TICKET_ROUTING_NUMBER- The GIB routing number for your program's deposit tickets. GIB gives you this at onboarding.- A front image of the deposit ticket. A rear image is optional.
- A sequence number for the ticket that is unique in the file, like any other item.
Step 2 - Build the deposit ticket¶
The ticket uses the same record layout as a check, so the simplest way to build it is to copy one of the bundle's check records and replace its values. The ticket's Addendum A must carry the receiving account as its BOFD account number. That is how the API recognizes the record as a ticket and does not record it as a check.
import copy
def make_deposit_ticket(checks, account_number, tran_code, sequence_number, front_image):
"""Build the deposit ticket for one bundle from the bundle's own check records.
TICKET_ROUTING_NUMBER is the GIB routing number for your program (see Step 1).
"""
ticket = copy.deepcopy(checks[0]) # Same record layout as the checks
ticket["payorBankRoutingNumber"] = TICKET_ROUTING_NUMBER[:8]
ticket["payorBankCheckDigit"] = TICKET_ROUTING_NUMBER[-1]
ticket["onUs"] = f"{account_number}/{tran_code}"
ticket["auxiliaryOnUs"] = ""
ticket["itemAmount"] = sum(check["itemAmount"] for check in checks) # Cents
ticket["eceInstitutionItemSequenceNumber"] = sequence_number
# One Addendum A, with the receiving account as the BOFD account
ticket["checkDetailAddendumA"] = ticket["checkDetailAddendumA"][:1]
ticket["checkDetailAddendumA"][0]["bofdAccountNumber"] = account_number
ticket["checkDetailAddendumB"] = []
ticket["checkDetailAddendumC"] = []
ticket["addendumCount"] = 1
# The ticket's own image: front view only
ticket["imageViewDetail"] = [front_image["detail"]]
ticket["imageViewData"] = [front_image["data"]]
ticket["imageViewAnalysis"] = []
return ticket
Step 3 - Add the ticket and update the totals¶
Put the ticket first in the bundle, then recompute the control records. The ticket is included in every item count and every total amount, so each total ends up at twice the value of the checks.
def balance_icl_file(icl_file, account_number, tran_code, next_sequence_number, ticket_image):
"""Add a deposit ticket to every bundle and update the control totals.
This example credits every bundle to the same account. To deposit to
several accounts, group each account's checks in their own bundle and
pass that bundle's account.
"""
file_items = file_amount = added_records = 0
for cash_letter in icl_file["cashLetters"]:
letter_items = letter_amount = 0
for bundle in cash_letter["bundles"]:
checks = bundle["checks"]
ticket = make_deposit_ticket(
checks, account_number, tran_code, next_sequence_number(), ticket_image
)
bundle["checks"] = [ticket] + checks
bundle_items = len(bundle["checks"])
bundle_amount = sum(item["itemAmount"] for item in bundle["checks"])
bundle["bundleControl"]["bundleItemsCount"] = bundle_items
bundle["bundleControl"]["bundleTotalAmount"] = bundle_amount
letter_items += bundle_items
letter_amount += bundle_amount
# Type 25 + one Type 26 + one Type 50/52 pair for the front image
added_records += 4
cash_letter["cashLetterControl"]["cashLetterItemsCount"] = letter_items
cash_letter["cashLetterControl"]["cashLetterTotalAmount"] = letter_amount
file_items += letter_items
file_amount += letter_amount
icl_file["fileControl"]["totalItemCount"] = file_items
icl_file["fileControl"]["fileTotalAmount"] = file_amount
icl_file["fileControl"]["totalRecordCount"] += added_records
return icl_file
If your files also carry image counts (bundleImagesCount, cashLetterImagesCount), add the ticket's image to those too.
For the two-check bundle above, the result is:
| Record | Items | Amount |
|---|---|---|
| Bundle control (70) | 3 | $600.00 |
| Cash letter control (90) | 3 | $600.00 |
| File control (99) | 3 | $600.00 |
Step 4 - Check it, then submit¶
Run the file through file/create with simulate set to true first. A simulation creates nothing and returns the Transactions the file would create. It should list your checks and not the ticket. If the ticket appears as a Transaction, its Addendum A BOFD account number does not match the account in its On-Us field, or its amount does not equal the rest of the bundle.
url = f"{ICL_API_URL}/file/create"
headers = {
"Content-type": "application/json",
"Authorization": f"{API_KEY}",
}
payload = {
"data": balanced_icl_file,
"test": False,
"simulate": True, # Remove to submit for real
"external_key": "DEPOSIT-2026-10-14-001",
}
response = requests.request("POST", url, json=payload, headers=headers)
response.raise_for_status()
Once the simulation looks right, remove simulate and submit. Use file/create-bulk for files of more than about 100 checks.
What you will see afterwards¶
- In the API: one ICL Transaction per check. The ticket is not a Transaction.
- On the account: one deposit per ticket, for the ticket amount.
GIB matches the bundle's checks to that one deposit when it posts. See How a balanced file posts.