# USDC / USDT / USDG로 RPC 결제하기: AI 에이전트를 위한 프로그래밍 방식 충전

> Source: https://docs.blockvectra.com/ko/guides/agent-topup/

개발자와 AI 에이전트는 HTTP를 통해 RPC 및 Data API 계정에 충전할 수 있습니다. 지원되는 네트워크와 토큰을 확인하고, 기존 API key를 사용하여 계정의 EVM 입금 주소를 가져온 후, 자금을 전송하고 크레딧 반영 상태를 폴링합니다. 충전하기 전에 [요금 페이지](https://blockvectra.com/en/pricing/)를 확인하고 [CU 가중치 기반 RPC 및 Data API 비용 추정 가이드](https://docs.blockvectra.com/en/guides/reading-cu-pricing/)를 참고하세요.

## 결제 관리(Billing)에서 입금 주소 확인

로그인 후 [결제 관리 페이지를 열어 입금 주소를 확인](https://console.blockvectra.com/login/?next=%2Fbilling%2F)하고, 계정에 표시된 입금 주소와 토큰 정보를 사용하세요. 자금을 전송하기 전에 [GET /v1/topup/status](https://api.blockvectra.com/v1/topup/status)에서 현재 지원되는 네트워크, 토큰 및 최소 충전 금액을 확인하세요.

> **API key 보안 및 서버 환경 호출 제한**
>
> `x-api-key` 헤더는 **서버 환경에서만 호출할 수 있습니다**. 클라이언트 브라우저 코드에서 충전 엔드포인트를 호출하지 마시고, 프론트엔드 번들, 공개 저장소 또는 AI 채팅 대화에 API key를 절대 노출하지 마세요.


## 사전 준비 사항

* **기존 API key**: 인증이 필요한 충전 엔드포인트를 호출하려면 활성화된 BlockVectra RPC API key가 필요합니다. 아직 API key가 없다면 [프로그래밍 방식 회원가입 가이드](https://docs.blockvectra.com/en/guides/programmatic-signup/)를 따라 이더리움 지갑 서명으로 가입하고 키를 생성하거나, [콘솔](https://console.blockvectra.com/login/?next=%2Fkeys%2F)에서 키를 생성하세요.
* **온체인 자산**: 에이전트 환경 또는 충전 지갑에 지원 네트워크의 `GET /v1/topup/status`에 나열된 USDC / USDT / USDG와 트랜잭션을 전송하기에 충분한 네이티브 가스 토큰을 보유하고 있어야 합니다.
* **환경 변수**: API key를 `BLOCKVECTRA_API_KEY` 환경 변수에 저장하세요.

인증이 필요한 충전 엔드포인트는 RPC 호출에 사용하는 것과 동일한 API key를 `x-api-key` 헤더로 직접 수신합니다. 브라우저 세션은 필요하지 않습니다.

## 4단계 충전 워크플로

첫 유료 충전이 반영되면 무료 주기 충전이 중단되고, 사용하지 않은 무료 크레딧은 유지되며, 계정 수준의 초당 호출 수 한도가 해제됩니다(키별 속도 제한은 그대로 유지됨). [요금 규칙](https://blockvectra.com/en/pricing/) 및 [무료 플랜 규칙](https://blockvectra.com/en/free/#rules)을 참조하세요. 현재 한도와 최소 충전 금액은 [GET /v1/plans](https://console-api.blockvectra.com/v1/plans)(`free`, `key_defaults`, `pricing.min_topup_usd`)에서 확인할 수 있습니다.

충전 엔드포인트(상태, 입금 주소, 입금 내역)는 프로덕션 API 호스트를 사용합니다:

```
https://api.blockvectra.com
```

플랜 한도 및 가격 책정 파라미터는 콘솔 API(`https://console-api.blockvectra.com`, 예: [GET https://console-api.blockvectra.com/v1/plans](https://console-api.blockvectra.com/v1/plans))에서 제공됩니다.

### 1. 충전 가능 여부 확인 (GET /v1/topup/status)

전송을 시작하기 전에 글로벌 충전 상태를 확인하고, 현재 열려 있는 네트워크와 토큰을 확인하며, 적용 중인 최소 입금 기준을 읽어오세요. 이 엔드포인트는 공개되어 있으며 인증 정보가 필요하지 않습니다.

```bash
curl -s https://api.blockvectra.com/v1/topup/status
```

응답 예시 (일부 네트워크 및 토큰 발췌):

```json
{
  "enabled": true,
  "networks": [
    {
      "network": "base_mainnet",
      "chain_id": 8453,
      "token": "USDC",
      "enabled": true
    },
    {
      "network": "bsc_mainnet",
      "chain_id": 56,
      "token": "USDT",
      "enabled": true
    },
    {
      "network": "bsc_mainnet",
      "chain_id": 56,
      "token": "USDC",
      "enabled": true
    }
  ]
}
```

* `enabled`: 글로벌 스위치입니다. `false`이면 모든 네트워크에서 충전이 중단됩니다.
* `networks`: 네트워크 및 토큰별 활성화 상태입니다. 특정 네트워크나 토큰의 `enabled`가 `false`이면 **해당 네트워크로 자금을 전송하지 마세요**.
* `min_deposit_usd`: 소수점 6자리로 표시된 글로벌 최소 입금 금액(USD)입니다. 최소 입금 기준은 동적입니다. 항상 `GET https://api.blockvectra.com/v1/topup/status`에서 실시간으로 반환되는 `min_deposit_usd`를 기준으로 삼으세요.

현재 적용 중인 `min_deposit_usd`를 직접 확인하려면:

```bash
curl -s https://api.blockvectra.com/v1/topup/status | jq -r .min_deposit_usd
```

### 2. 입금 주소 및 파라미터 조회 (GET /v1/topup/deposit-address)

고객 전용 EVM 입금 주소를 조회하거나 할당받고, 지원 네트워크 및 토큰 컨트랙트를 확인합니다. 이 엔드포인트는 `x-api-key` 인증이 필요하며 서버 환경에서만 호출해야 합니다.

```bash
curl -s \
  -H "x-api-key: $BLOCKVECTRA_API_KEY" \
  https://api.blockvectra.com/v1/topup/deposit-address
```

응답 예시 (일부 네트워크 및 토큰 발췌):

```json
{
  "address": "0x<your-dedicated-deposit-address>",
  "deposits_url": "https://api.blockvectra.com/v1/topup/deposits",
  "networks": [
    {
      "chain": "base_mainnet",
      "chain_id": 8453,
      "name": "Base",
      "typical_credit_seconds": 30,
      "explorer_tx_url": "https://basescan.org/tx/{tx_hash}",
      "tokens": [
        {
          "symbol": "USDC",
          "contract": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
          "decimals": 6,
          "min_amount_raw": "1000000"
        }
      ]
    },
    {
      "chain": "bsc_mainnet",
      "chain_id": 56,
      "name": "BNB Smart Chain",
      "typical_credit_seconds": 60,
      "explorer_tx_url": "https://bscscan.com/tx/{tx_hash}",
      "tokens": [
        {
          "symbol": "USDT",
          "contract": "0x55d398326f99059fF775485246999027B3197955",
          "decimals": 18,
          "min_amount_raw": "1000000000000000000"
        },
        {
          "symbol": "USDC",
          "contract": "0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d",
          "decimals": 18,
          "min_amount_raw": "1000000000000000000"
        }
      ]
    }
  ]
}
```

* `address`: EIP-55 체크섬이 적용된 계정 전용 EVM 입금 주소입니다.
* `deposits_url`: 고객 입금 내역을 조회하는 URL입니다.
* `networks`: 활성화된 EVM 네트워크 목록입니다. 지원되지 않는 네트워크는 제외됩니다. 체인 식별자 `chain`, EVM 체인 ID `chain_id`, 표시 이름 `name`, 블록 포함 후 일반적인 반영 지연 시간(초) `typical_credit_seconds`, 블록 탐색기 트랜잭션 URL 템플릿 `explorer_tx_url`을 포함합니다.
* `tokens`: 해당 네트워크의 토큰 목록입니다. 토큰 심볼 `symbol`(USDC / USDT / USDG), 컨트랙트 주소 `contract`, 토큰 소수점 자리수 `decimals`, 기본 최소 입금 단위 `min_amount_raw`를 포함합니다(단위를 임의로 가공하지 말고 엔드포인트에서 반환된 실제 값을 참조하세요).

> **토큰 소수점 자리수 및 금액 변환**
>
> 동일한 토큰이라도 체인에 따라 소수점 자리수(decimals)가 다를 수 있습니다(예: BSC의 USDT 및 USDC는 18자리이지만, Base의 USDC는 6자리입니다). 금액 계산 시 단일 토큰 소수점 값을 하드코딩하지 말고 해당 네트워크에서 반환된 `decimals`를 반드시 사용해야 합니다.


#### 오류 응답

인증이 필요한 충전 엔드포인트(`/v1/topup/deposit-address` 및 `/v1/topup/deposits`)는 표준 JSON 오류 구조를 반환합니다:

* **HTTP 401 (인증 실패)**: `x-api-key` 헤더가 누락되었거나(`missing_api_key`), 키가 유효하지 않거나 취소 또는 비활성화된 경우(`invalid_api_key`) 반환됩니다:

```json
{
  "error": {
    "code": "missing_api_key",
    "message": "missing API key: send it in the x-api-key header",
    "data": {
      "reason": "missing_api_key",
      "docs_url": "https://docs.blockvectra.com/en/errors/#missing_api_key",
      "retryable": false
    }
  }
}
```

* **HTTP 409 (충전 비활성화)**: 전역적으로 또는 모든 네트워크에서 충전이 중단된 경우(`topup_disabled`) 반환됩니다:

```json
{
  "error": {
    "code": "topup_disabled",
    "data": {
      "reason": "topup_disabled",
      "docs_url": "https://docs.blockvectra.com/en/errors/#topup_disabled",
      "retryable": false
    }
  }
}
```

전체 오류 코드 목록은 [오류 레퍼런스](https://docs.blockvectra.com/en/errors/)를 참조하세요.

### 3. 온체인 전송 트랜잭션 브로드캐스트

에이전트의 지갑이나 스크립트를 사용하여 2단계에서 가져온 입금 `address`로 ERC-20 `transfer` 트랜잭션을 전송합니다.

전송 요구사항:

* 해당 네트워크의 `tokens` 배열에 나열된 토큰과 컨트랙트로만 전송하세요.
* 전송 금액이 해당 네트워크의 토큰 `decimals`에 맞춰 `min_amount_raw` 이상인지 확인하세요(`GET /v1/topup/deposit-address`에서 반환된 실제 값 또는 `GET /v1/topup/status`에서 반환된 `min_deposit_usd` 기준).
* 지원되지 않는 체인으로 전송하거나 잘못된 토큰을 전송하면 자동으로 반영되지 않습니다. 트랜잭션을 브로드캐스트하기 전에 네트워크와 토큰 컨트랙트를 반드시 확인하세요.
* 트랜잭션이 제출되면 온체인 트랜잭션 해시(`tx_hash`)를 기록하세요.

### 4. 입금 내역 폴링 및 반영 확인 (GET /v1/topup/deposits)

트랜잭션이 블록에 포함된 후 입금 내역을 조회하여 반영 상태를 추적합니다. 이 엔드포인트는 `x-api-key`가 필요하며 서버 환경 전용입니다.

#### 쿼리 파라미터

* `limit`: 페이지당 반환할 입금 내역 수입니다. 기본값은 `20`이며, 유효 범위는 `1`–`100`입니다.
* `before`: `deposit_id` 기반 커서 페이지네이션 파라미터입니다. 이전 페이지 응답의 `next_before` 값을 전달하여 이전 내역의 다음 페이지를 가져옵니다.
* `tx_hash`: 특정 전송 건을 필터링하기 위한 0x 접두사가 붙은 64자리 16진수 트랜잭션 해시(선택 사항)입니다.

트랜잭션 해시(`tx_hash`)로 필터링하여 특정 전송 건을 확인합니다:

```bash
curl -s \
  -H "x-api-key: $BLOCKVECTRA_API_KEY" \
  "https://api.blockvectra.com/v1/topup/deposits?tx_hash=0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890"
```

응답 예시:

```json
{
  "items": [
    {
      "deposit_id": 42,
      "chain": "base_mainnet",
      "chain_id": 8453,
      "token": "USDC",
      "contract": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
      "amount": "25.000000",
      "tx_hash": "0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890",
      "tx_log_ordinal": 0,
      "block_number": 123456789,
      "external_ref": "eip155:8453:0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890:0",
      "status": "credited",
      "reason": null,
      "credited_units": 250000,
      "credited_cu": 250000000,
      "detected_at": "2026-10-02T10:00:00Z"
    }
  ],
  "next_before": null
}
```

* `items`: 쿼리 파라미터와 일치하는 입금 내역 배열입니다.
* `next_before`: 이전 내역이 더 있는 경우 다음 페이지를 위한 커서 ID이며, 더 이전 내역이 없으면 `null`입니다. 커서 기반 페이지네이션을 위해 `before` 쿼리 파라미터와 함께 사용하세요.

입금 `status` 값:

* `processing`: 온체인에서 전송이 감지되어 반영 처리가 진행 중입니다.
* `credited`: 계정 잔액에 반영되었습니다. `credited_units`와 `credited_cu`는 반영된 수량을 나타냅니다.
* `not_credited`: 전송이 반영될 수 없습니다. `reason` 필드에서 원인을 확인할 수 있습니다:
  * `below_minimum`: 입금 금액이 최소 기준액 미만입니다.
  * `large_amount`: 입금 금액이 기준치를 초과하여 수동 검토가 필요합니다.
  * `other`: 기타 입금 처리 예외입니다.

반영 지연 시간 및 폴링 지침:

* **도착 및 반영 소요 시간**: 반영 시간은 2단계에서 반환된 `typical_credit_seconds`의 적용을 받습니다.
* **폴링 주기**: 속도 제한을 트리거하지 않도록 더 자주 호출하지 말고 **20–60초 간격**으로 폴링하는 것을 권장합니다.

## 코드 예제

다음 예제는 환경 변수에서 `BLOCKVECTRA_API_KEY`를 읽어 Node.js와 Python에서 충전 엔드포인트를 조회하는 방법을 보여줍니다.

### Node.js (fetch)

```javascript
import process from "node:process";

const apiKey = process.env.BLOCKVECTRA_API_KEY;
if (!apiKey) {
  throw new Error("Missing BLOCKVECTRA_API_KEY environment variable");
}

const BASE_URL = "https://api.blockvectra.com";

// 1. Check availability and read minimum deposit threshold
const statusRes = await fetch(`${BASE_URL}/v1/topup/status`);
const status = await statusRes.json();
if (!status.enabled) {
  throw new Error("Top-up is currently disabled");
}
const minDepositUsd = status.min_deposit_usd;
console.log("Minimum deposit (USD):", minDepositUsd);

// 2. Retrieve deposit address and open networks
const addressRes = await fetch(`${BASE_URL}/v1/topup/deposit-address`, {
  headers: { "x-api-key": apiKey },
});

if (addressRes.status === 401) {
  throw new Error("Missing or invalid API key (HTTP 401)");
}
if (addressRes.status === 409) {
  throw new Error("Top-up is disabled (topup_disabled)");
}
if (!addressRes.ok) {
  throw new Error(`Failed to retrieve deposit address: ${addressRes.status}`);
}

const depositData = await addressRes.json();
console.log("Deposit address:", depositData.address);
console.log("Open networks count:", depositData.networks.length);

// 3. Poll deposit status
async function checkDepositStatus(txHash) {
  const url = new URL(`${BASE_URL}/v1/topup/deposits`);
  url.searchParams.set("tx_hash", txHash);

  const res = await fetch(url, {
    headers: { "x-api-key": apiKey },
  });
  if (res.status === 401) {
    throw new Error("Missing or invalid API key (HTTP 401)");
  }
  if (!res.ok) {
    throw new Error(`Failed to query deposits: ${res.status}`);
  }
  return res.json();
}
```

### Python (requests)

```python
# pip install requests
import os
import requests

api_key = os.environ.get("BLOCKVECTRA_API_KEY")
if not api_key:
    raise ValueError("Missing BLOCKVECTRA_API_KEY environment variable")

base_url = "https://api.blockvectra.com"

# 1. Check availability and read minimum deposit threshold
resp = requests.get(f"{base_url}/v1/topup/status", timeout=10)
resp.raise_for_status()
status_data = resp.json()
if not status_data.get("enabled"):
    raise RuntimeError("Top-up is currently disabled")
min_deposit_usd = status_data.get("min_deposit_usd")
print("Minimum deposit (USD):", min_deposit_usd)

# 2. Retrieve deposit address
resp = requests.get(
    f"{base_url}/v1/topup/deposit-address",
    headers={"x-api-key": api_key},
    timeout=10,
)
if resp.status_code == 401:
    raise RuntimeError("Missing or invalid API key (HTTP 401)")
if resp.status_code == 409:
    raise RuntimeError("Top-up is disabled (topup_disabled)")
resp.raise_for_status()
deposit_data = resp.json()
print("Deposit address:", deposit_data["address"])

# 3. Poll deposit status
def check_deposit_status(tx_hash: str):
    resp = requests.get(
        f"{base_url}/v1/topup/deposits",
        headers={"x-api-key": api_key},
        params={"tx_hash": tx_hash},
        timeout=10,
    )
    if resp.status_code == 401:
        raise RuntimeError("Missing or invalid API key (HTTP 401)")
    resp.raise_for_status()
    return resp.json()
```

## 다음 단계

* [잔액 조회 (`GET /v1/account`)](https://docs.blockvectra.com/en/guides/billing-rules/#query-balance-get-v1account): 계정 잔액 및 남은 Compute Unit (CU) 확인.
* [청구 규칙](https://docs.blockvectra.com/en/guides/billing-rules/): Compute Unit (CU) 측정, 속도 제한 및 과금되지 않는 오류 검토.
* [무료 플랜 가이드](https://docs.blockvectra.com/en/guides/free-plan/): 무료 티어 한도 및 업그레이드 규칙 검토.
* [프로그래밍 방식 회원가입 가이드](https://docs.blockvectra.com/en/guides/programmatic-signup/): 지갑 서명을 사용한 계정 생성 및 API key 발급.
