> ## Documentation Index
> Fetch the complete documentation index at: https://cobo.com/payments/llms.txt
> Use this file to discover all available pages before exploring further.

# Top-up

This page covers Top-up Mode: each payer has their own deposit address, and every deposit is tracked on its own. Read [Events overview](https://cobo.com/payments/payments/en/guides/events/overview.md) first for the envelope, deduplication, and the rules that apply to every event.

## Events on this page

| Event | What it notifies you of | Type |
| - | - | - |
| [`payment.topup.updated`](#payment-topup-updated) | A top-up's status changed: detected, in compliance screening, action required, completed, or failed. | **Standard** |
| [`payment.address.updated`](#payment-address-updated) | You replaced a payer's deposit address via the update top-up address API. | **Standard** |

## `payment.topup.updated`

The main event for Top-up Mode.

### Trigger conditions

**One event per change of this deposit's `status`.**

![Top-up status flow](https://mintcdn.com/mcpnow/VoBPAZOrg_70X0ZK/payments/en/images/payments/events/top-up-status.svg?fit=max\&auto=format\&n=VoBPAZOrg_70X0ZK\&q=85\&s=822205309b3714a8a4bed097e9838488)

The diagram shows the main status paths; final statuses are shown in green. An intermediate status (such as `PendingScreening`) may not appear if the deposit moves on to the next status quickly, and events may arrive out of order; see [Event ordering](https://cobo.com/payments/payments/en/guides/events/overview.md#event-ordering).

| Trigger condition | `status` | Creditable | What to do |
| - | - | - | - |
| The funds are detected on a deposit address | `Detected` | ❌ | Record the incoming deposit. |
| The deposit enters compliance screening (no second event is sent when it returns here after `ActionRequired` is resolved) | `PendingScreening` | ❌ | Wait. |
| Screening needs you to act — supply information, or complete a manual compliance review | `ActionRequired` | ❌ | Act on `message`. |
| Screening passed and the transaction has at least one on-chain confirmation | `Completed` (final) | ✅ | Credit `amount`, using `transaction_id` as the idempotency key. |
| The deposit was rejected or failed | `Failed` (final) | ❌ | Read `failed_reason.code` to decide what happens next. |

**A deposit at or below the dust threshold sends no event.** Each token's threshold is the `min_amount` returned by [Create/Get top-up address](https://cobo.com/payments/payments/en/api-references/payment/createget-top-up-address.md) or [Batch create top-up addresses](https://cobo.com/payments/payments/en/api-references/payment/batch-create-top-up-addresses.md); tokens without their own setting default to `0.05`, and an amount must exceed it.

### Event content

| Field | Type | Description |
| - | - | - |
| `data_type` | `string` | Always `PaymentTopUpUpdate`. |
| `transaction_id` | `string` | The deposit's ID in Cobo. |
| `merchant_id` | `string` | Which merchant this deposit belongs to. |
| `payer_id` | `string` | The payer ID assigned by Cobo. |
| `custom_payer_id` | `string` | The payer ID you supplied when registering the deposit address; `null` if you supplied none. |
| `status` | `string` | The current status; see [Trigger conditions](#trigger-conditions) for what each means: • `Detected` • `PendingScreening` • `ActionRequired` • `Completed` • `Failed` |
| `amount` | `object` | The deposit's amount. It never changes and is kept even when the deposit fails. |
| `amount.amount` | `string` | The amount. See [Amounts](https://cobo.com/payments/payments/en/guides/events/overview.md#amounts) for the format. |
| `amount.token_id` | `string` | The token ID. |
| `amount.chain_id` | `string` | The chain ID. |
| `tx_hash` | `string` | The on-chain transaction hash. |
| `topup_address` | `string` | The deposit address that received the funds. |
| `source_address` | `string` | The on-chain sender, and the target if you return the funds. |
| `screening_mode` | `string` | The screening method, used to tell where to handle the deposit when `status` is `ActionRequired`. • `CoboKyt` — Cobo KYT. • `IntegratedVendor` — a third-party provider integrated by Cobo in the Screening App. |
| `message` | `string` | What to do when `status` is `ActionRequired`; `null` otherwise. • `Additional information is required…` — check the email Cobo sent to your account contact and supply what it asks for. • `A manual compliance review by your team is required…` — complete a manual compliance review in the Screening App. |
| `failed_reason` | `object` | Set when `status` is `Failed`; `null` otherwise. |
| `failed_reason.code` | `string` | The failure code. See [Failure reasons](#failure-reasons) for the values. |
| `failed_reason.message` | `string` | The failure reason. |
| `created_timestamp` | `integer` | When this deposit was created, in Unix timestamp (seconds). |
| `updated_timestamp` | `integer` | When this deposit last changed status, in Unix timestamp (seconds). |

### Failure reasons

| `code` | What happened | What to do |
| - | - | - |
| `transaction.rejected_by_screening_app` | Your own compliance team rejected this deposit in the [Screening App](https://manuals.cobo.com/en/apps/screening/introduction). | Review the case there. |
| `transaction.rejected_by_compliance` | Cobo's compliance checks rejected this deposit. | Check with Cobo. |
| `transaction.failed` | Failed for any other reason. | Raise a case and quote `transaction_id`. |

### Sample events

Each sample shows the `data` object only. The envelope around it is the same for every event — see [Event structure](https://cobo.com/payments/payments/en/guides/events/overview.md#event-structure).

#### A deposit is detected

Mark it as in progress. Do not credit anything yet.

```json theme={null}
{
  "data_type": "PaymentTopUpUpdate",
  "transaction_id": "aff0e1cb-15b2-4e1f-9b9d-a9133715986f",
  "merchant_id": "M1001",
  "payer_id": "P20250619T0310056d7aa",
  "custom_payer_id": "user_abc_10001",
  "status": "Detected",
  "amount": { "amount": "100", "token_id": "ETH_USDC", "chain_id": "ETH" },
  "tx_hash": "0xabc123",
  "topup_address": "0xtopup_addr_M1001_user_abc",
  "source_address": "0xsender001",
  "screening_mode": null,
  "message": null,
  "failed_reason": null,
  "created_timestamp": 1744689000,
  "updated_timestamp": 1744689000
}
```

#### Compliance screening is in progress

Keep waiting. `screening_mode` tells you which system is reviewing it, not that you need to do something.

```json theme={null}
{
  "data_type": "PaymentTopUpUpdate",
  "transaction_id": "aff0e1cb-15b2-4e1f-9b9d-a9133715986f",
  "merchant_id": "M1001",
  "payer_id": "P20250619T0310056d7aa",
  "custom_payer_id": "user_abc_10001",
  "status": "PendingScreening",
  "amount": { "amount": "100", "token_id": "ETH_USDC", "chain_id": "ETH" },
  "tx_hash": "0xabc123",
  "topup_address": "0xtopup_addr_M1001_user_abc",
  "source_address": "0xsender001",
  "screening_mode": "IntegratedVendor",
  "message": null,
  "failed_reason": null,
  "created_timestamp": 1744689000,
  "updated_timestamp": 1744689060
}
```

#### Screening needs you to act

Route the deposit into your manual handling process and use `message` to decide which action is needed.

```json theme={null}
{
  "data_type": "PaymentTopUpUpdate",
  "transaction_id": "aff0e1cb-15b2-4e1f-9b9d-a9133715986f",
  "merchant_id": "M1001",
  "payer_id": "P20250619T0310056d7aa",
  "custom_payer_id": "user_abc_10001",
  "status": "ActionRequired",
  "amount": { "amount": "100", "token_id": "ETH_USDC", "chain_id": "ETH" },
  "tx_hash": "0xabc123",
  "topup_address": "0xtopup_addr_M1001_user_abc",
  "source_address": "0xsender001",
  "screening_mode": "CoboKyt",
  "message": "Additional information is required before these funds can be made available. Please check the email sent to your account contact.",
  "failed_reason": null,
  "created_timestamp": 1744689000,
  "updated_timestamp": 1744689100
}
```

#### The funds are available

**This is the only status you may credit on.** Use `transaction_id` as the idempotency key.

```json theme={null}
{
  "data_type": "PaymentTopUpUpdate",
  "transaction_id": "aff0e1cb-15b2-4e1f-9b9d-a9133715986f",
  "merchant_id": "M1001",
  "payer_id": "P20250619T0310056d7aa",
  "custom_payer_id": "user_abc_10001",
  "status": "Completed",
  "amount": { "amount": "100", "token_id": "ETH_USDC", "chain_id": "ETH" },
  "tx_hash": "0xabc123",
  "topup_address": "0xtopup_addr_M1001_user_abc",
  "source_address": "0xsender001",
  "screening_mode": null,
  "message": null,
  "failed_reason": null,
  "created_timestamp": 1744689000,
  "updated_timestamp": 1744689300
}
```

#### The deposit failed

Stop any automatic crediting and read `failed_reason.code`. Here Cobo's compliance checks rejected it, so do not resend — resolve it with Cobo first.

```json theme={null}
{
  "data_type": "PaymentTopUpUpdate",
  "transaction_id": "aff0e1cb-15b2-4e1f-9b9d-a9133715986f",
  "merchant_id": "M1001",
  "payer_id": "P20250619T0310056d7aa",
  "custom_payer_id": "user_abc_10001",
  "status": "Failed",
  "amount": { "amount": "100", "token_id": "ETH_USDC", "chain_id": "ETH" },
  "tx_hash": "0xabc123",
  "topup_address": "0xtopup_addr_M1001_user_abc",
  "source_address": "0xsender001",
  "screening_mode": null,
  "message": null,
  "failed_reason": {
    "code": "transaction.rejected_by_compliance",
    "message": "This transaction was rejected by Cobo's compliance checks. Please do not resubmit it; contact Cobo support to resolve the issue first."
  },
  "created_timestamp": 1744689000,
  "updated_timestamp": 1744689400
}
```

## `payment.address.updated`

Fires after you replace a payer's deposit address via [Update top-up address](https://cobo.com/payments/payments/en/api-references/payment/update-top-up-address.md). When you receive it, update that payer's deposit address in your system to `updated_address`.

### Address event content

| Field | Type | Description |
| - | - | - |
| `data_type` | `string` | Always `PaymentAddressUpdate`. |
| `merchant_id` | `string` | Which merchant the payer belongs to. |
| `payer_id` | `string` | The payer whose address changed, as assigned by Cobo. |
| `custom_payer_id` | `string` | The same payer's ID in your own system, `null` if you supplied none. |
| `chain` | `string` | The chain the address is on. Only the address on this chain changed. |
| `previous_address` | `string` | The address before the replacement. |
| `updated_address` | `string` | The address to show the payer from now on. |

```json theme={null}
{
  "data_type": "PaymentAddressUpdate",
  "merchant_id": "M1001",
  "payer_id": "P20250619T0310056d7aa",
  "custom_payer_id": "user_abc_10001",
  "chain": "ETH",
  "previous_address": "0xtopup_addr_M1001_user_abc",
  "updated_address": "0xtopup_addr_M1001_user_abc_new"
}
```

## Advanced events

For confirmation counts, on-chain transaction fee breakdowns, and other on-chain transaction detail, subscribe to the advanced events `payment.transaction.created`, `payment.transaction.completed`, and `payment.transaction.failed`. See [Advanced events](https://cobo.com/payments/payments/en/guides/events/advanced.md).
