Reconciling PayIns in Colombia means matching the Money Movement created for a collection (Direct Link, Checkout, or R2P) against the credit Transaction it produces on your Cobre Balance — with two important exceptions: static Cobre Keys and Transfer-In account references, neither of which ever creates a Money Movement.
Money Movements vs. Transactions#
| Identifier | Prefix | Generated when | Represents |
|---|
| Money Movement ID | mm_ | The PayIn (Direct Link, Checkout, or R2P) is created | The collection intent and its lifecycle status |
| Transaction ID | trx_ | The PayIn completes and funds are credited | The actual balance-affecting ledger entry |
Always provide external_id when creating a PayIn Money Movement. It's echoed back and is the simplest way to match a Cobre collection to your internal invoice or order.
This doesn't apply to static Cobre Keys or Transfer-In account references — see below. Neither has a Money Movement or an external_id; each reconciles on its own reference field instead (metadata.key_value for Cobre Keys, metadata.account_reference for Transfer-In).
Example — how a Direct Link PayIn (PSE) and its Transaction unfold, step by step:1
Money Movement created
{
"id": "mm_z4ICqZzfIdG4A3",
"external_id": "ORDER-2025-050",
"type": "direct_link",
"geo": "col",
"status": {
"state": "initiated",
"code": "",
"description": ""
},
"source_id": "cp_5YFeIDhNkz",
"destination_id": "acc_SsMCnqmUvS",
"currency": "cop",
"amount": 10000,
"created_at": "2025-10-31T01:14:10Z",
"updated_at": "2025-10-31T01:14:10Z"
}
2
Payer completes the payment — credit Transaction applied
{
"id": "trx_lTTesMeNSbn1zA5RWeOX",
"type": "r2p_credit",
"account_id": "acc_SsMCnqmUvS",
"amount": 10000,
"previous_balance": 0,
"current_balance": 10000,
"currency": "cop",
"credit_debit_type": "credit",
"transaction_date": "2025-10-31T01:14:50Z",
"created_at": "2025-10-31T01:14:51Z",
"metadata": {
"sender_bank_code": "1019",
"money_movement_id": "mm_z4ICqZzfIdG4A3",
"description": "CustomRef123",
"sender_name": "John Doe",
"r2p_method": "pse",
"tracking_key": "1890417980",
"sender_id": "97710251"
}
}
The Transaction's metadata.money_movement_id (mm_z4ICqZzfIdG4A3) is what ties it back to the Money Movement — this is the field you group by when reconciling.3
Money Movement reaches completed
{
"id": "mm_z4ICqZzfIdG4A3",
"external_id": "ORDER-2025-050",
"type": "direct_link",
"geo": "col",
"status": {
"state": "completed",
"code": "",
"description": ""
},
"source_id": "cp_5YFeIDhNkz",
"destination_id": "acc_SsMCnqmUvS",
"currency": "cop",
"amount": 10000,
"created_at": "2025-10-31T01:14:10Z",
"updated_at": "2025-10-31T01:14:51Z"
}
Compare this against a static Cobre Key or Transfer-In collection below, neither of which has a Money Movement or a money_movement_id at all.
Colombia Credit Transaction Types#
Depending on the collection method, a completed PayIn in Colombia produces one of these Transaction types:| Transaction type | Collection method | Backed by a Money Movement? |
|---|
col_credit | Connect Account credit (bank-reported) | Yes |
col_cb_credit | Cobre Balance credit (Direct Link / Checkout — PSE, Bancolombia) | Yes |
r2p_credit | Request to Pay (PSE) | Yes |
dd_credit | Direct Debit registration collection | Yes |
col_top_up_credit | Top up | Yes |
r2p_breb_credit | Bre-B Direct Link / Checkout (Request to Pay over Bre-B) | Yes |
breb_credit | Static Cobre Key | No — see below |
transfer_credit | Transfer-In account reference | No — see below |
breb_credit and r2p_breb_credit carry the payer's sender data (sender_name, sender_id, sender_account_number) directly on the Transaction. This is the only Colombia rail family where sender data is available without an extra lookup — see Processing Refunds in Colombia.Static Cobre Keys Don't Create a Money Movement#
A Cobre Key is a static Bre-B key: once created, anyone holding it can send money to it at any moment, without Cobre initiating or tracking a specific payment request. Because there's no request to track, no Money Movement is created for a Cobre Key collection — it simply produces a breb_credit Transaction directly on your Cobre Balance, with metadata.key_value set to the Cobre Key that received the funds.Example — a breb_credit Transaction from a static Cobre Key collection:{
"id": "trx_sVT1Gn3qzHLpll6ThICH",
"type": "breb_credit",
"amount": 5000,
"previous_balance": 0,
"current_balance": 5000,
"currency": "cop",
"credit_debit_type": "credit",
"transaction_date": "2025-11-26T01:17:17Z",
"created_at": "2025-11-26T01:17:17Z",
"metadata": {
"sender_account_number": "87041725528",
"sender_account_type": "dp",
"sender_bank_code": "1507",
"sender_id": "97710251",
"sender_id_type": "cc",
"sender_name": "JOHN DOE",
"key_value": "@CB5VLNRMCOBRECOMERCI",
"description": ""
}
}
There is no money_movement_id anywhere on this Transaction. metadata.key_value (@CB5VLNRMCOBRECOMERCI in this example) is your reconciliation key instead — it identifies which of your Cobre Keys received the payment.
Transfer-In Account References Don't Create a Money Movement Either#
A Transfer-In account reference is a real, reusable Colombian bank account number that Cobre provisions for you (up to 300 per client). It has no expiration and can receive B2B bank transfers at any moment — like a static Cobre Key, there's no Cobre-initiated request behind each transfer, so no Money Movement is created. Every incoming transfer simply produces a transfer_credit Transaction directly on your Cobre Balance, with metadata.account_reference set to the Transfer-In reference that received the funds.Example — a transfer_credit Transaction from a Transfer-In collection:{
"id": "trx_f840c6adace259a504a56bdb6xxxxx",
"type": "transfer_credit",
"amount": 54700,
"previous_balance": 4712500,
"current_balance": 4767200,
"currency": "cop",
"credit_debit_type": "credit",
"transaction_date": "2026-05-19T19:48:07Z",
"created_at": "2026-05-19T19:48:08Z",
"metadata": {
"reference": "0038212345",
"sender_name": "PEXTO COLOMBIA S",
"sender_id": "9011830296",
"sender_bank_code": "1066",
"tracking_key": "291000003C6051234567",
"description": "NC TRAN ELEC INTERNA",
"account_reference": "291000123"
}
}
There is no money_movement_id anywhere on this Transaction. metadata.account_reference (291000123 in this example) is your reconciliation key — it identifies which Transfer-In account reference received the funds. The Transaction also carries the payer's sender_name, sender_id, and sender_bank_code directly, with no extra lookup needed.
key_value (Cobre Keys) and account_reference (Transfer-In) are not interchangeable — each product only populates its own field. Don't write reconciliation logic that checks one field as a fallback for the other; branch on the Transaction type (breb_credit vs. transfer_credit) first.
PayIn Lifecycle and Balance Impact#
A Colombia PayIn Transaction is only created when the Money Movement reaches completed — this applies to every Money-Movement-backed collection method (Direct Link, Checkout, R2P, Direct Debit):| Terminal state | Transaction created? | Net balance impact |
|---|
completed | Yes — 1 credit | Positive (funds received) |
rejected / failed | No | None |
Static Cobre Keys and Transfer-In account references don't go through this lifecycle at all — see above.
Refunds Affect Reconciliation Too#
Colombia has no dedicated refund endpoint. Refunding a completed PayIn means creating a new PayOut Money Movement back to the payer, which produces its own debit Transaction, separate from the original credit. When reconciling, don't assume a completed PayIn's balance impact is permanent — check for a later, related PayOut before closing out the period. See Processing Refunds in Colombia for the full flow.
Reconciling Colombia PayIns#
On demand: For Money-Movement-backed PayIns, query Obtain all Money Movements filtered by state, external_id, destination_id (your Cobre Balance), or a date range, then cross-reference Obtain an Account Transactions filtered by credit_debit_type=credit and metadata.money_movement_id. For Cobre Keys or Transfer-In, query Transactions directly and filter/group by metadata.key_value or metadata.account_reference respectively — there's no Money Movement to query for either.In bulk: Generate a Money Movement report (money_movement_csv_v1 for CSV, or money_movement_v1 for JSON) and a Transaction report (transactions_csv_v1 for CSV, or account_transactions_v1 for JSON) via Reports, and filter the exported rows to currency = COP. Group Money-Movement-backed rows by metadata.money_movement_id — a completed PayIn should have exactly one credit row. Cobre Key rows won't have a money_movement_id; group those by metadata.key_value. Transfer-In rows won't have one either; group those by metadata.account_reference.In real time: Subscribe to Notifications & Subscriptions instead of polling. For Money-Movement-backed PayIns, money_movements.status.completed (and .rejected / .failed) fires as soon as the status changes. Cobre Keys and Transfer-In have no Money Movement to emit a status event for — use accounts.balance.credit instead, and match it back to the right Cobre Key or Transfer-In reference using the event's metadata.key_value or metadata.account_reference. For Transfer-In specifically, also subscribe to transfer_acc.status.processing / .enabled / .failed to track when a reference itself becomes ready to share with a payer — separate from the transfer credits it later receives.Webhook delivery is best-effort, not guaranteed forever — see Notifications & Subscriptions for the retry window. Treat webhooks as your real-time signal and on-demand queries or Reports as the periodic fallback that catches anything a webhook missed.
Allowed Actions on Payin Reconciliation in Colombia#
🔍 Retrieval — Money Movements
🔍 Retrieval — Transactions
Description: Query Colombia PayIns on demand by state, external ID, destination Cobre Balance, or date range. Does not apply to static Cobre Key or Transfer-In collections.
What to expect after the action: A paginated list of Money Movement objects with their current status. How to Get Started#
1
Know which collection methods create a Money Movement
Direct Link, Checkout, R2P, and Direct Debit do; static Cobre Keys and Transfer-In account references don't. Plan your reconciliation key accordingly: money_movement_id for the former, metadata.key_value (Cobre Keys) or metadata.account_reference (Transfer-In) for the latter two.
2
Always provide external_id on Money-Movement-backed PayIns
It's searchable via the external_id filter and the simplest way to match a collection to your internal order or invoice.
3
Subscribe to Money Movement status events instead of polling
4
Track refunds as separate PayOuts
Since Colombia has no dedicated refund endpoint, watch for follow-up PayOuts referencing a previously completed PayIn.
What to expect after using this API#
1
Completed PayIns match one-to-one with a credit Transaction
Rejected or failed PayIns produce no balance-affecting Transaction. Cobre Key and Transfer-In collections skip this lifecycle entirely.
2
Cobre Key and Transfer-In collections reconcile by their own reference field, not money_movement_id
Every breb_credit Transaction carries metadata.key_value; every transfer_credit Transaction carries metadata.account_reference. The two fields are never interchangeable.
3
Refunded PayIns surface as a linked follow-up PayOut
Reconciliation for a given period accounts for both the original credit and any later refund debit.