# 페이지 나누기와 캐시는 어떻게 합니까: 커서, ETag, If-None-Match?

REST API · next_cursor를 따라가고, ETag로 재검증하며, no-store는 ‘다시 요청하라’로 읽기

*에이전트용 · 5분 · 고급 · 개발자 · 페이지 나누기*

목록 피드는 `next_cursor`로 페이지를 나눕니다: 같은 쿼리를 `cursor=`와 함께 반복하고, 커서가 없는 페이지에서 멈추십시오. GET 응답에는 ETag가 붙습니다 — 비용이 적은 304를 받으려면 `If-None-Match`를 보내십시오(2026-10-13 /v1/sanctions에서 확인) — 단, §4가 `no-store`로 표시한 응답은 예외입니다: 일부를 잃은 응답 — 다시 요청하십시오 — 과, 호출마다 계산되는 솔라나 판정, 그리고 결코 캐시되지 않는 몇 가지 조회(`/v1/stats/slo`, 오류 응답)로, 이 경우 `no-store`는 재시도에 대해 아무것도 말하지 않습니다 — `503 timeout`은 여전히 `Retry-After`를 담고 재시도를 요청합니다. `Cache-Control`을 정보로 읽으십시오: 판정에서 60 대신 `max-age=10`이면 노출 탐색이 중단되었다는 뜻입니다.

## 페이지 나누기

[정산 피드](https://achivx.kr/academy/guides/settlement-tables/), 기록 원장, [제안](https://achivx.kr/academy/guides/issuer-freezes/) 목록은 *최신순으로, 한 번에 한 페이지씩* 페이지를 나눕니다: `limit`(`/v1/transfers`와 원장에서 1–200, 기본값 50, *그 밖의 값은 `400`*. [피드](https://achivx.kr/academy/courses/following-the-stablecoins/following-the-stablecoins-01-settlement-tables/)에 대응하는 스킬 `get-recent-transactions`의 기본값은 25. 제안 목록은 1–500, 기본값 100이며 범위를 벗어난 값은 거부되지 않고 100으로 읽힘), `cursor` = *같은 필터로* 받은 이전 페이지의 `next_cursor`, 그리고 *`next_cursor`가 없는 페이지가 가장 오래된 페이지*입니다. 피드의 첫 페이지에는 `total`이 있습니다 — 2026-10-13 이더리움(Ethereum) 피드는 `capped: true`와 함께 `total: 25000`으로 답했습니다 — 명세는 `capped`를 불리언으로만 정의하므로 그 옆의 수치를 전체 개수로 읽지 마십시오 — 그리고 *제때 끝나지 않은 개수 집계는 `total_unavailable_reason: "timeout"`과 함께 `"total": null`입니다 — 행은 실제이고, 페이지는 `no-store`이며, `next_cursor`로 계속 페이지를 넘기십시오*. 커서는 불투명하며, 제안 목록의 커서는 봉인되어 있습니다: 서비스 프로세스가 재시작되기 전에 발급된 커서는 `400 invalid_cursor`로 답할 수 있습니다 — 최신 페이지부터 다시 시작하십시오. `limit`을 올리기보다 페이지를 넘기십시오: 제안 목록에는 *멀티시그가 지금까지 제안한 모든 것이 아니라 감시기가 인덱싱한 것*이 들어 있고, 피드에서 가장 오래된 페이지는 `hot_window_start`에서 끝납니다 — 더 오래된 행은 오프로드되었습니다.

## 캐시

*GET 응답(REST와 페이지)은 ETag로 캐시됩니다 — 비용이 적은 `304`를 받으려면 `If-None-Match`를 보내십시오 — 단, §4가 `no-store`로 표시한 응답은 예외입니다.* 모든 REST 응답에는 `Access-Control-Expose-Headers: ETag`가 있어 브라우저 클라이언트도 재검증에 쓸 태그를 읽을 수 있으며, 엣지가 약한 태그(`W/"…"`)를 넘겨주더라도 일치합니다. 태그는 본문에서 만들어지므로 *주소 응답(그 `freshness_seconds`가 매초 바뀜)은 거의 일치하지 않습니다. `/v1/sanctions`, `/v1/methodology`, 카드, 재생된 그래프 조회는 일치합니다.* 2026-10-13 측정: `/v1/sanctions`는 ETag와 함께 `public, max-age=300`으로 답했고, `If-None-Match`를 붙인 같은 요청은 `304`로 답했습니다.

그날 경로별 헤더: `/v1/sync/status` `max-age=5`; `/v1/transfers`와 `/v1/verify` `max-age=15`; `/v1/freezes/acts`와 `/v1/freezes/proposals` `max-age=30`; 주소 개요와 판정, `/v1/stats/home`, `/v1/freezes/networks`, `/v1/search` `max-age=60`(`/balances`는 `max-age=30`); `/v1/sanctions`와 `/v1/subscriptions` `max-age=300`; `/v1/networks`와 `/v1/tokens` `max-age=300, stale-while-revalidate=60, stale-if-error=3600`; `/v1/tokens/{token}/routes` `max-age=3600`; `/v1/stats/slo`와 오류 응답 — `/v1/watchlists`의 인증되지 않은 `401` 포함 — `no-store`. 그리고 캐시에서 본 중단 사례, 실제로: 매뉴얼이 쓰는 트레저리(이더리움의 0x5754…b949)의 위험 판정은 [노출 탐색](https://achivx.kr/academy/guides/exposure-card/)이 시간 예산을 소진해 `max-age=10`으로 답했습니다.

## no-store의 의미

정직성 계약의 규칙: 일부를 잃은 응답은 `no-store`로 제공됩니다 — 다시 요청하십시오 — 라벨 없는 판정, 읽기가 끝나지 않아 `chains_with_data`나 `freshness_seconds`가 `null`인 주소 또는 동기화 응답, `"total": null`인 피드 페이지, `degraded_reason`이 있는 `/graph`가 그렇습니다. *같은 요청을 잠시 뒤에 하면 완전할 수 있습니다.* `/v1/stats/home`이나 `/v1/stats/overview`의 `null`은 다릅니다: 배치의 상태이며, 다시 요청해도 채워지지 않습니다. REST `/risk`와 `/exposure`에서 60 대신 `Cache-Control: max-age=10`은 캐시에서 본 중단된 [노출 탐색](https://achivx.kr/academy/guides/exposure-card/)입니다 — 그리고 응답 자체가 모든 접근 경로에서 이를 밝힙니다. *`incomplete_reasons`의 `time_budget`. A2A와 MCP에는 이를 위한 헤더가 없습니다*. 그러니 헤더가 아니라 필드로 분기하십시오. `computed_at`은 판정이 계산된 시점이므로 *더 자주 폴링한다고 더 새로운 판정을 얻지는 못합니다*.

## Stablecoin scanner ACHIVX에서

[피드 페이지를 JSON으로 열기 ↗](https://stablescan.achivx.com/v1/transfers?chain=1&limit=5)

- `next_cursor`, `total`, `hot_window_start`가 있는 피드 페이지: [/v1/transfers?chain=1&limit=5](https://stablescan.achivx.com/v1/transfers?chain=1&limit=5).
- ETag가 재검증되는 응답: [/v1/sanctions](https://stablescan.achivx.com/v1/sanctions). 규칙: [/agents.md](https://stablescan.achivx.com/agents.md) §2와 §6.

## 출처

- [에이전트 매뉴얼 — agents.md (버전 2026-10-05)](https://stablescan.achivx.com/agents.md)
- [REST 인터페이스의 OpenAPI 3.1 명세 (API 1.4.0)](https://stablescan.achivx.com/openapi.json)
- [2026-10-13 조회한 응답 헤더 — ETag와 Cache-Control이 있는 /v1/sanctions](https://stablescan.achivx.com/v1/sanctions)

## 더 알아보기

- [가이드: 정산 표](https://achivx.kr/academy/guides/settlement-tables/)
- [레슨: 페이로드에서 정직성 계약 읽기](https://achivx.kr/academy/courses/the-scanner-for-agents/the-scanner-for-agents-03-reading-the-honesty-contract/)

## 관련 질문

- [get-recent-transactions는 무엇을 반환합니까?](https://achivx.kr/academy/for-agents/get-recent-transactions/)
- [한도는 무엇이며, 거부는 어떤 모습입니까?](https://achivx.kr/academy/for-agents/what-are-the-limits-and-refusals/)
- [정직성 계약이란 무엇입니까?](https://achivx.kr/academy/for-agents/what-is-the-honesty-contract/)

REST API · 페이지 나누기 · 2026-10-13 작성, 스캐너 자체의 기계용 문서와 그날 조회한 실시간 응답을 바탕으로 했습니다. 구조는 그대로 인용했으며, 수치는 날짜 기준이고 인덱스에 따라 바뀝니다.

---

출처: https://achivx.kr/academy/for-agents/how-to-page-and-cache/ · 영어 원문: https://achivx.com/academy/for-agents/how-to-page-and-cache.html
