Deposits
Give a party a reusable Bre-B key: the pesos it pays there arrive as USDC on Celo in its wallet.
With the deposit product, a party pays Colombian pesos from its own bank and receives USDC on
Celo in its wallet. TuCOP gives the party a deposit account: a Bre-B key, issued by the
provider for that party, tied to one wallet. The account is created once per wallet and reused.
Every request needs your consumer key and a party session. Opening a
deposit account (POST /deposits) also needs the deposit product, or it gets
403 product_not_enabled, and a party that finished identity verification. Reading your accounts
(GET /deposits, GET /deposits/{id}) needs neither.
Get the deposit account
curl https://api.ramp.tucop.xyz/deposits \
--request POST \
--header "X-TuCOPRamp-Key: $TUCOPRAMP_API_KEY" \
--header "X-TuCOPRamp-Party-Session: $PARTY_SESSION" \
--header "Idempotency-Key: $(uuidgen)" \
--header "Content-Type: application/json" \
--data '{}'
{
"id": "dep_01j9z3k8q2m4n6p8r0s2t4v6w8",
"product": "deposit",
"status": "active",
"deposit_instructions": {
"rail": "bre_b",
"currency": "COP",
"bre_b_key": "00901234567890123456",
"account_holder_name": "Provider account holder",
"bank_name": null
},
"destination": {
"address": "0x1111111111111111111111111111111111111111",
"chain": "eip155:42220",
"asset": "USDC",
"token_contract": "0xcebA9300f2b948710d2653dD7B07f33A8B32118C"
},
"fee_bps": 150,
"created_at": "2026-10-10T20:00:00.000Z"
}
Show the party deposit_instructions.bre_b_key and the holder name. Whatever it pays there, from
its own bank account, arrives as USDC at destination.address, less TuCOP's fee and the
provider's spread. fee_bps is TuCOP's fee in basis points. TuCOP sets it for each integrator, and it is fixed
when the account is created.
The wallet defaults to the one the session was opened with. Pass wallet_address to use another
wallet, or when the session was not opened with a wallet; a different wallet gets its own account.
A deposit account belongs to your integrator: another integrator linked to the same party gets its
own account for the same wallet, with its own fee, and neither sees the other's. Your app answers for the address: TuCOP checks only
that it is one, and USDC sent to a wrong address cannot be recovered. The first call answers 201,
later calls 200 with the same account.
An account the provider already has
The party may already have a deposit account at the payments provider, opened outside TuCOP. When
it has an active one that takes pesos and sends USDC on Celo to the wallet_address you ask for
(compared without regard to case), and no integrator holds it yet, POST /deposits takes that
account over instead of opening another one. It answers 200, with that account's Bre-B key, and
fee_bps is that account's own fee, which can differ from your integrator's fee. From then on it
is your integrator's account like any other: later calls answer 200 with the same account. An
account another integrator already holds is never taken over; you get a new one (201).
Change the wallet
To keep the same Bre-B key and send the USDC to another wallet, use PATCH /deposits/{id}:
curl https://api.ramp.tucop.xyz/deposits/dep_01j9z3k8q2m4n6p8r0s2t4v6w8 \
--request PATCH \
--header "X-TuCOPRamp-Key: $TUCOPRAMP_API_KEY" \
--header "X-TuCOPRamp-Party-Session: $PARTY_SESSION" \
--header "Idempotency-Key: $(uuidgen)" \
--header "Content-Type: application/json" \
--data '{ "wallet_address": "0x2222222222222222222222222222222222222222" }'
It answers 200 with the account and its new destination.address. Pesos paid from then on
arrive at the new wallet. The same wallet answers 200 with the account unchanged. Only the
integrator that opened (or took over) the account can change it, and it needs the deposit
product. wallet_address is checked as on POST /deposits, and your app answers for it. An
Idempotency-Key is required, as on POST.
TuCOP refuses the change with 409 deposit_in_flight while money may still be on its way to the
current wallet, so a deposit is never split between two wallets:
- a deposit whose latest activity is
funds_scheduled,funds_received,in_revieworpayment_submitted(the pesos arrived and the USDC was not delivered or refunded yet), or - any money activity on the account in the last 2 minutes.
Retry after the deposit shows payment_processed or refund in GET /deposits/{id}, and two
minutes have passed. The error includes the account as deposit. No webhook is sent for the
change: the answer confirms it.
Follow the deposits
GET /deposits lists the party's deposit accounts, newest first, at most 50, without activity.
GET /deposits/{id} returns the account with events: the provider's activity on it, most
recent first.
{
"id": "dep_01j9z3k8q2m4n6p8r0s2t4v6w8",
"product": "deposit",
"status": "active",
"deposit_instructions": {
"rail": "bre_b",
"currency": "COP",
"bre_b_key": "00901234567890123456",
"account_holder_name": "Provider account holder",
"bank_name": null
},
"destination": {
"address": "0x1111111111111111111111111111111111111111",
"chain": "eip155:42220",
"asset": "USDC",
"token_contract": "0xcebA9300f2b948710d2653dD7B07f33A8B32118C"
},
"fee_bps": 150,
"created_at": "2026-10-10T20:00:00.000Z",
"events": [
{
"id": "7c1e9a52-3f0b-4d6e-8a2c-5b9d0e1f2a3b",
"type": "funds_received",
"amount": { "amount": "100000.00", "asset": "COP" },
"created_at": "2026-10-11T15:04:10.003Z"
}
]
}
| Field | Meaning |
|---|---|
status | active, or deactivated when TuCOP turned the account off. There is no endpoint to deactivate one. A deactivated account is no longer read from the provider, so it sends no more webhooks. |
events[].id | The activity line. The same value is event_id in the webhook. |
events[].type | The provider's name for the activity, for example funds_received. Treat it as text: new values can appear. |
events[].amount | In COP when the provider reports pesos, otherwise in USDC. null when the provider gave no amount. |
GET /deposits answers the same objects without events, in data:
{
"data": [
{
"id": "dep_01j9z3k8q2m4n6p8r0s2t4v6w8",
"product": "deposit",
"status": "active",
"...": "..."
}
]
}
Each activity line also arrives as a deposit.received webhook, once, to the consumer that created
the account, as soon as the provider reports it. TuCOP also reads the account from the provider
about once a minute while it is active, and every 30 minutes after a day without activity, so a
line whose notice was missed still arrives; either way it is sent once. The webhook's
destination_address says which wallet the USDC goes to.
Errors
| Code | Status | When |
|---|---|---|
invalid_wallet_address | 400 | wallet_address is not a 0x address. |
product_not_enabled | 403 | Your consumer does not have deposit. |
deposit_not_found | 404 | Not the party's, or not there. |
deposit_in_flight | 409 | PATCH: money may still be on its way to the current wallet. See Change the wallet. |
deposit_not_owned | 409 | PATCH: an older account no single integrator owns. Contact TuCOP. |
deposit_deactivated | 409 | PATCH: the account is deactivated. |
deposit_wallet_in_use | 409 | PATCH: you already have a deposit account for the party and that wallet. |
party_not_verified | 409 | Identity verification is not finished. |
wallet_address_required | 422 | The session has no wallet and none was passed. |
provider_rejected | 422 | The provider refused to create or change the account. |
provider_unavailable | 502 | Retry. On PATCH, also when the provider did not accept the change: the wallet stays as it was. |