# 주소의 거래 상대는 어떻게 가져옵니까: /graph 또는 /walk?

주소 · 노드와 엣지로 된 에고 하위 그래프, 또는 홉 단위 탐색 — 한 번에 토큰 하나, 주소 500개의 탐색 경계, 그리고 응답이 밝히는 기간 범위

*API 가이드 · 10분 · 중급 · 개발자 · GET …/graph · GET …/walk*

`/v1/addresses/{address}/graph?chain=&token=&hops=`는 주소 주변의 정산 그래프를 `nodes[]`와 `edges[]`(엣지별 거래량, 노드별 라벨, `motifs[]`)로 반환합니다. 최신 스냅샷이 저장되어 있으면 그것으로 만들고, 무거운 그래프가 아직 없으면 `202 building`으로 답합니다. `/v1/addresses/{address}/walk?chain=&token=&hops=`는 같은 이웃을 홉 단위로 반환하며, 요청마다 새로 만들고 `stop_at_attributed`와 `stop_on_sanctioned` 스위치를 가집니다. 두 라우트 모두 `token`을 전달하십시오. 그래프는 스테이블코인별로 만들어집니다. 무언가가 없다는 것에서 결론을 내리기 전에 `window_from`을 읽으십시오.

## 그래프

```
curl -s 'https://stablescan.achivx.com/v1/addresses/0x28C6c06298d514Db089934071355E5743bf21d60/graph?chain=1&token=USDT&hops=1'
```

2026-10-24 바이낸스(Binance) 핫월렛의 USDT 이웃입니다. 노드 484개와 엣지 484개이며, 앞부분만 잘라 보여 줍니다.

```
{
  "address": "0x28c6c06298d514db089934071355e5743bf21d60",
  "chain_id": 1,
  "token": "USDT",
  "decimals": 6,
  "window": "all",
  "window_from": "2026-10-03",
  "edge_source": "daily",
  "max_hops": 1,
  "frontier_cap": 500,
  "start_key": "addr:28c6c06298d514db089934071355e5743bf21d60",
  "nodes": [
    {"key": "addr:28c6…1d60", "address": "0x28c6…1d60", "hop": 0, "volume": 0, "volume_usd6": 0, "score": 1, "attributed": false, "sanctioned": false,
     "name": "Binance", "category": "exchange_hot", "is_service": true},
    {"key": "addr:5754…b949", "address": "0x5754…b949", "hop": 1, "direction": "out", "volume": 500000000000000, "volume_usd6": 500000000000000, "score": 0.0431,
     "attributed": false, "sanctioned": false, "name": "Tether: Treasury", "category": "issuer", "is_service": true}
  ],
  "edges": [
    {"from": "addr:28c6…1d60", "to": "addr:5754…b949", "volume": 500000000000000, "volume_usd6": 500000000000000, "tx_count": 1}
  ],
  "motifs": [],
  "extraction": {"hops": 1, "nodes_explored": 484, "frontier_truncated": true, "stop_at_attributed": true, "edges_omitted": false},
  "built_at": "2026-10-24T08:22:06Z",
  "snapshot_served": true,
  "snapshot_age_seconds": 8696
}
```

**`nodes[]`** — `key`와 `address`, 노드에 도달한 `hop`, `direction`(`in`: 대상에게 지급함, `out`: 대상이 지급함), 토큰 최소 단위의 `volume`과 `volume_usd6`, `score`(대상의 흐름 중 노드의 몫, 대상 자신은 1), `attributed`와 `sanctioned`, 그리고 라벨이 있으면 라벨이 들어 있습니다. **`edges[]`** — `from`, `to`, 거래량, `tx_count`. **`motifs[]`** — 자금 세탁 형태 적중으로, 섀도 신호이며 여기서는 비어 있습니다. **`extraction`** — 그림이 어떻게 잘렸는지를 나타냅니다. `frontier_truncated: true`는 [홉](https://achivx.kr/academy/reference/glossary/#g-hop) 1이 `frontier_cap`(기본값이자 최댓값 500)보다 넓어서 가장 큰 거래 상대들만 남겼다는 뜻입니다.

**`edge_source`, `window`, `window_from`** — 그래프를 무엇으로 만들었는지를 나타냅니다. `lifetime`은 지금까지 인덱싱된 모든 날의 전체 기간 합계입니다(조용한 주소인 제재 대상 예시는 노드 하나, 엣지 없이 `edge_source: "lifetime"`으로 답했습니다). `daily`는 일 단위이며, 이때 `window_from`이 시작 지점을 알려 줍니다. 요청은 `window=all`이었지만 여기서는 `2026-10-03`입니다. 연결 수 기준을 넘는 메가 허브는 항상 `daily`입니다. `lifetime_deferred: true`는 전체 이력이 백그라운드에서 만들어지는 중인, 기간 `all`에 대한 일 단위 응답을 표시합니다.

**`snapshot_served`, `snapshot_age_seconds`, `built_at`** — 이 그림은 저장된 것이며 2.4시간 지난 것입니다. 그래프가 저장되어 있지 않고 기한 안에 만들어지지 않는 무거운 주소는 `{"status": "building", "retry_after_seconds": 5, …}`와 `Retry-After: 5`로 **`202`**를 답합니다. 그래프도 아니고 오류도 아닙니다. 기다린 뒤 같은 요청을 반복하십시오. 노드를 읽기 전에 상태를 확인하십시오. `X-Degraded` 헤더와 함께 오는 `degraded_reason`은 응답의 일부가 빠졌다는 뜻이며, 그 응답은 `no-store`입니다.

`hops`는 0–4(기본값 1)이고, `window`는 `1h`, `24h`, `7d`, `30d`, `90d`, `1y`, `all` 중 하나이며, `frontier`는 너비의 [상한](https://achivx.kr/academy/reference/limits/)을 정합니다(0이거나 파싱할 수 없으면 500 유지). `token`이 없으면 네트워크의 기본 스테이블코인이 쓰이므로 전달하십시오.

## 탐색

```
curl -s 'https://stablescan.achivx.com/v1/addresses/0x28C6c06298d514Db089934071355E5743bf21d60/walk?chain=1&token=USDC&hops=1&frontier_cap=20'
```

```
{
  "address": "0x28c6c06298d514db089934071355e5743bf21d60",
  "chain_id": 1,
  "token": "USDC",
  "decimals": 6,
  "token_source": "explicit",
  "window": "all",
  "window_from": "2026-10-03",
  "max_hops": 1,
  "frontier_cap": 20,
  "stop_at_attributed": true,
  "stop_on_sanctioned": false,
  "start_key": "addr:28c6c06298d514db089934071355e5743bf21d60",
  "self_sanctioned": false,
  "hops": [
    {"hop": 1, "nodes": [
      {"key": "addr:6a36…d9aa", "address": "0x6a36…d9aa", "direction": "in", "volume": 99200000, "volume_usd6": 99200000, "score": 0.6005, "attributed": false, "service": false, "sanctioned": false},
      {"key": "addr:b03f…2337", "address": "0xb03f…2337", "direction": "in", "volume": 66000000, "volume_usd6": 66000000, "score": 0.3995, "attributed": false, "service": false, "sanctioned": false}
    ]}
  ],
  "nodes_explored": 2,
  "frontier_truncated": false
}
```

[탐색](https://achivx.kr/academy/reference/glossary/#g-walk)은 노드를 `hops[]`별로 묶고 스위치 값을 그대로 돌려줍니다. `stop_at_attributed`(기본값 `true`: 라벨이 붙은 서비스는 경계이며, 확인은 하지만 통과해 탐색하지 않음), `stop_on_sanctioned`(기본값 `false`), `frontier_cap` 1–500, `hops` 0–4(기본값 2)입니다. `token_source`는 토큰이 여러분이 지정한 것(`explicit`)인지 네트워크 기본값인지 알려 줍니다. `self_sanctioned`는 대상 자신이 목록에 올라 있는지입니다. 요청마다 새로 만들어지므로 마지막 집계 처리 시점의 일 단위 데이터를 반영합니다. 솔라나(Solana)에서는 채움이 끝나면 다음 처리(약 10분) 후 `walk`에 나타나고, `graph`에는 그 이후 그래프가 새로 만들어져야 나타납니다.

[첫 요청](https://achivx.kr/academy/api/first-request/)의 세 가지 헬퍼로 같은 호출을 하면 다음과 같습니다.

**Python**

```
import time
g = scan(f"/v1/addresses/{addr}/graph", chain=1, token="USDT", hops=1)
if g.get("status") == "building":         # a 202 — urllib does not raise on it
    time.sleep(g["retry_after_seconds"]); g = scan(f"/v1/addresses/{addr}/graph", chain=1, token="USDT", hops=1)
print(g.get("window_from"), g["extraction"]["nodes_explored"], "nodes;", len(g["edges"]), "edges")
top = sorted((n for n in g["nodes"] if n["hop"] == 1), key=lambda n: -n["volume_usd6"])[:5]
for n in top:
    print(" ", n["direction"], n.get("name") or n["address"], n["volume_usd6"] / 1e6)
```

**Go**

```
var g struct {
	Status     string `json:"status"` // "building" on a 202
	WindowFrom string `json:"window_from"`
	Nodes      []struct {
		Address   string  `json:"address"`
		Hop       int     `json:"hop"`
		Direction string  `json:"direction"`
		VolumeUSD float64 `json:"volume_usd6"`
		Name      string  `json:"name"`
	} `json:"nodes"`
	Edges []struct {
		From, To string
		TxCount  int `json:"tx_count"`
	} `json:"edges"`
}
err := get("/v1/addresses/"+addr+"/graph", url.Values{"chain": {"1"}, "token": {"USDT"}, "hops": {"1"}}, &g)
if err != nil {
	return err
}
if g.Status == "building" {
	time.Sleep(5 * time.Second) // then repeat the same request
}
```

**TypeScript**

```
type Node = { address: string; hop: number; direction?: "in" | "out"; volume_usd6: number; name?: string; sanctioned: boolean };
type Graph = { status?: "building"; retry_after_seconds?: number; window_from?: string; nodes: Node[]; edges: { from: string; to: string; tx_count: number }[] };
let g = await scan<Graph>(`/v1/addresses/${addr}/graph`, { chain: 1, token: "USDT", hops: 1 });
if (g.status === "building") {
  await new Promise((r) => setTimeout(r, (g.retry_after_seconds ?? 5) * 1000));
  g = await scan<Graph>(`/v1/addresses/${addr}/graph`, { chain: 1, token: "USDT", hops: 1 });
}
```

Python의 `urllib`는 `202`를 성공으로 처리하므로, 만들어지는 중인 그래프와 실제 그래프를 구분해 주는 것은 위의 `status` 확인입니다. Go와 TypeScript 헬퍼도 `202`가 400 미만이므로 같은 방식으로 동작합니다.

## 무엇을 호출할 것인가

- **그림** — 노드, 엣지, 거래량, 가장 활발한 거래 상대: `/graph`. 저장된 것이므로 반복 호출이 저렴하며, 몇 시간 지난 것일 수 있습니다(`snapshot_age_seconds`, 최대 6시간, 빌드 실패 시 대체용은 72시간).
- **경로에 대한 질문** — *홉 2에 누가 있는가, 탐색이 서비스에서 멈췄는가, 경로상에 제재 대상이 있는가*: `/walk`. 목록에 오른 첫 노드에서 멈추려면 `stop_on_sanctioned=true`를 씁니다. 요청마다 만들어지며 `frontier_cap`으로 제한됩니다.
- 거래 상대가 의미하는 바에 대한 **판정**: 둘 다 아닙니다. [`/exposure`](https://achivx.kr/academy/api/address-exposure/)가 [오염 출발점](https://achivx.kr/academy/reference/glossary/#g-taint-root)까지 역방향으로 [탐색하고](https://achivx.kr/academy/reference/glossary/#g-walk) 분류를 답합니다. 여기의 두 라우트는 그림만 그립니다.

## 이런 것이 보이면 …

- **`window=all` 요청에 `"window_from": "2026-10-03"`** — 일 단위 데이터는 고정된 기간 범위만큼 보관됩니다([`/v1/methodology`](https://stablescan.achivx.com/v1/methodology)에서는 이를 `edge_grain_horizon`이라고 부릅니다). 응답은 그 구간만 다룹니다. 그 안에 없는 거래 상대를 그 날짜 이전에도 없었던 것으로 취급하지 마십시오.
- **`"frontier_truncated": true`** — [홉](https://achivx.kr/academy/reference/glossary/#g-hop)이 상한보다 넓었습니다. 가장 큰 거래 상대만 남았고 나머지는 그림에 없습니다. `window`를 좁히거나 특정 `token`으로 `/walk`를 요청하십시오.
- **`token "USDC" is not indexed on chain 728126428`과 함께 `400 bad_request`** — 해당 스테이블코인이 이 네트워크의 [레지스트리](https://achivx.kr/academy/reference/glossary/#g-registry)에 없습니다. 무엇이 있는지는 `/v1/tokens?chain=`이 나열합니다.
- **솔라나** — 대상의 `coverage_status`가 함께 옵니다. `pending`은 그림이 더 커질 수 있다는 뜻입니다.

## Stablecoin scanner ACHIVX에서

- JSON 형태의 그래프: [/graph?chain=1&token=USDT&hops=1](https://stablescan.achivx.com/v1/addresses/0x28C6c06298d514Db089934071355E5743bf21d60/graph?chain=1&token=USDT&hops=1); [탐색](https://achivx.kr/academy/reference/glossary/#g-walk): [/walk?chain=1&token=USDC&hops=1&frontier_cap=20](https://stablescan.achivx.com/v1/addresses/0x28C6c06298d514Db089934071355E5743bf21d60/walk?chain=1&token=USDC&hops=1&frontier_cap=20).
- 같은 그래프를 그린 것 — 흐름 보기와 트리 보기, *drawing 32 of 479+*: [/ethereum/address/0x28C6…1d60](https://stablescan.achivx.com/ethereum/address/0x28C6c06298d514Db089934071355E5743bf21d60).

## 출처

- [REST 인터페이스의 OpenAPI 3.1 명세(API 1.4.0)](https://stablescan.achivx.com/openapi.json)
- [에이전트 매뉴얼 — agents.md(버전 2026-10-05)](https://stablescan.achivx.com/agents.md)
- [GET /v1/methodology (stablscan-methodology-v0.5.0)](https://stablescan.achivx.com/v1/methodology)

## 더 알아보기

- [가이드: 거래 상대 그래프](https://achivx.kr/academy/guides/counterparty-graph/)
- [get-wallet-graph-walk는 무엇을 반환합니까?](https://achivx.kr/academy/for-agents/get-wallet-graph-walk/)
- [한도](https://achivx.kr/academy/reference/limits/)

## 관련 질문

- [주소의 제재 대상 자금이나 해킹 자금 노출은 어떻게 측정합니까?](https://achivx.kr/academy/api/address-exposure/)
- [주소의 스테이블코인 잔액과 거래량은 어떻게 읽습니까?](https://achivx.kr/academy/api/address-balances-and-volume/)
- [스테이블코인 하나의 최대 보유 주소와 가장 활발한 경로는 어떻게 가져옵니까?](https://achivx.kr/academy/api/token-rankings/)

주소 · GET …/graph · GET …/walk · 2026-10-24 작성, openapi.json, agents.md 및 당일 실제 호출 기준. 응답 형태는 인용이며, 수치는 날짜 기준이고 인덱스에 따라 달라집니다.

---

출처: https://achivx.kr/academy/api/address-graph-and-walk/ · 영어 원문: https://achivx.com/academy/api/address-graph-and-walk.html
