REST API
Arcscan читает Arc через HTTP-API, и этот API доступен снаружи без ключа и без аккаунта — каждый путь на этой странице был вызван через публичный интернет прежде, чем был записан.
Базовый URL#
У API есть собственные имена хостов, по одному на сеть: api.arc-scan.io — основная сеть Arc, идентификатор 5042, и api-testnet.arc-scan.io — Arc Testnet, идентификатор 5042002. Строиться нужно именно на них:
https://api.arc-scan.io/v1 # Arc mainnet, chain 5042 https://api-testnet.arc-scan.io/v1 # Arc Testnet, chain 5042002
Каждый хост отдаёт одни и те же две поверхности: /v1/… — типизированный REST API, по одному пути на ресурс, возвращающий те же документы, из которых рисуется сам обозреватель, — и /api?module=…&action=… — совместимый контракт, на котором уже говорят существующие инструменты. Хосты различаются только сетью, за которую отвечают, поэтому перевод клиента на тестовую сеть — это смена хоста и ничего больше.
Собственный путь сайта /_api — это не API
Можно заметить, что обозреватель обращается к /_api/v1/… со своего же источника и что этот путь отвечает, если позвать его вручную. Это внутренний маршрут сайта к той же самой службе, оставленный для его собственных страниц: он не отдаёт ни одного заголовка CORS, отдаётся с заголовком noindex и может быть изменён по причине, никак с вами не связанной. Стройтесь на именах хостов выше и держите хост в одной константе, чтобы менять его в одном месте.Из браузера вызывается — но только по этим хостам
Хосты API отвечают на кросс-доменные запросы:Access-Control-Allow-Origin: *, в предварительном запросе разрешены Content-Type, X-Api-Key и If-None-Match, а вызывающему открыты ETag, X-Request-Id и заголовки лимитов. Собственный путь обозревателя /_api не несёт ни одного заголовка Access-Control-, поэтому fetch() по нему в браузере падает, тогда как тот же вызов через curl проходит, — именно так неверный адрес и остаётся незамеченным.Два интерфейса#
Одна и та же нода и один и тот же индекс отвечают в двух разных формах. Типизированный API — это то, из чего отрисовывается сам обозреватель, поэтому всё видимое на странице читается как JSON в том же виде. Совместимый API воспроизводит де-факто стандартный REST-контракт эксплореров, на котором уже говорят кошельки, скрипты деплоя и индексаторы, поэтому существующие инструменты переводятся на Arc сменой одного базового URL.
| Интерфейс | Форма | Оболочка успешного ответа |
|---|---|---|
/v1/… | Типизированный REST, по одному пути на ресурс | Сам документ, ключи в snake_case |
/api?module=…&action=… | Один путь, диспетчеризация по строке запроса | {"status":"1","message":"OK","result":…} |
Эндпоинты#
Каждый путь ниже был вызван к основной сети при написании этой страницы. Ответили все; два ответили 501, и оба названы там, где им место, а не выброшены — задокументированный отказ дороже пробела.
Сеть, главная и голова цепи#
/v1/chain — это первый вызов, который стоит сделать: он называет идентификатор сети, нативную валюту и число её знаков, возможности этой установки и то, какая именно часть цепи проиндексирована. Читайте его, а не зашивайте всё это в код: две сети различаются, а раздел Полнота данных объясняет, о чём говорит блок с индексом.
curl https://api.arc-scan.io/v1/chain # {"chain_id":5042,"name":"Arc","is_testnet":false, # "native":{"symbol":"USDC","decimals":18}, # "block_time_ms":506,"finality":"instant", # "capabilities":{"trace":true,"archive":true,"debug":false,…}, # "index":{"available":true,"complete":true,…}}
| Путь | На что отвечает |
|---|---|
GET /v1/chain | Константы сети, возможности и покрытие индекса |
GET /v1/home | Последние блоки и транзакции в одном документе |
GET /v1/stats/summary | Основные счётчики, которые показывает главная страница |
GET /v1/stats/gas | Трекер комиссий: текущие и недавние цены газа |
GET /v1/stream/head | События server-sent, по одному кадру на новый блок |
/v1/stream/head — это поток SSE, а не документ JSON: он остаётся открытым и присылает кадр примерно дважды в секунду. Каждый кадр несёт server_now, чтобы клиент мог честно вычислить возраст, не доверяя собственным часам.
curl -N https://api.arc-scan.io/v1/stream/head # event: head # data: {"height": 14852424, "hash": "0x68ce06…f3775", "timestamp": 1786360005, # "tx_count": 0, "server_now": 1786360007, "available": true}
Блоки#
Ссылка на блок — это высота, хеш или литерал latest. Списки принимают limit и непрозрачный cursor; что значат поля, см. в разделе Блоки.
curl "https://api.arc-scan.io/v1/blocks?limit=2" curl https://api.arc-scan.io/v1/blocks/latest curl https://api.arc-scan.io/v1/blocks/14852000 curl "https://api.arc-scan.io/v1/blocks/14852000/txs?limit=10"
Транзакции#
Транзакция адресуется хешем. Дерево вызовов в основной сети доступно, потому что trace там истинно; разница состояния — нет, потому что debug ложно, и об этом сообщается кодом 501, а не пустым ответом.
H=0x128cb07da24289341bcc57e3129ef78f82b5a1769c30156774487fe9e98251e9 curl "https://api.arc-scan.io/v1/txs?limit=5" curl "https://api.arc-scan.io/v1/txs/$H" curl "https://api.arc-scan.io/v1/txs/$H/raw" curl "https://api.arc-scan.io/v1/txs/$H/trace" curl "https://api.arc-scan.io/v1/txs/$H/state" # 501 {"error":{"code":"CAPABILITY_UNAVAILABLE",…}} — no debug namespace on mainnet
Адреса и токены#
A=0xf40dc55b06e4e8c042430ecf1995d0ec6b9ae033 T=0x3600000000000000000000000000000000000000 # the native currency as an ERC-20 curl "https://api.arc-scan.io/v1/address/$A" curl "https://api.arc-scan.io/v1/address/$A/txs?limit=10" curl "https://api.arc-scan.io/v1/address/$A/activity?limit=10" curl "https://api.arc-scan.io/v1/address/$A/logs?limit=10" curl "https://api.arc-scan.io/v1/address/$A/tokens" curl "https://api.arc-scan.io/v1/tokens/$T" curl "https://api.arc-scan.io/v1/tokens/$T/info"
Держатели в основной сети проиндексированы, поэтому /v1/tokens/{address}/holders отвечает для обычных токенов. Для нативной валюты по адресу 0x3600…0000 он отказывает, и сообщение объясняет почему: эти балансы и есть балансы аккаунтов, а их повторная индексация посчитала бы каждый аккаунт дважды.
Поиск, графики и декодирование#
Поиск разрешает то же, что разрешает собственная строка обозревателя, — высоту, хеш, адрес. Индекс графиков перечисляет каждую метрику с её идентификатором, а /v1/charts/{metric} возвращает конкретный ряд; tx — одна из них. Декодирование — единственный POST на этой странице, и обращения к цепи ему не требуется вовсе.
curl "https://api.arc-scan.io/v1/search?q=0x3600000000000000000000000000000000000000" curl "https://api.arc-scan.io/v1/search/suggest?q=0x36" curl https://api.arc-scan.io/v1/charts curl https://api.arc-scan.io/v1/charts/tx curl -X POST https://api.arc-scan.io/v1/decode \ -H 'content-type: application/json' \ -d '{"input":"0xa9059cbb…"}' # {"selector":"0xa9059cbb","decoded":{"name":"transfer", # "signature":"transfer(address,uint256)","args":[…]},"error":null}
Совместимый интерфейс#
/api?module=…&action=… говорит на знакомом контракте эксплореров: один путь, module и action, и каждое скалярное значение в result — строка. Модуль proxy пропускает чтения JSON-RPC насквозь и отвечает в форме JSON-RPC, а не в оболочке со статусом.
curl "https://api.arc-scan.io/api?module=proxy&action=eth_blockNumber" # {"jsonrpc":"2.0","id":1,"result":"0xe2a12f"} curl "https://api.arc-scan.io/api?module=account&action=balance&address=0xf40dc55b06e4e8c042430ecf1995d0ec6b9ae033" # {"status":"1","message":"OK","result":"20456053552414099311"} curl "https://api.arc-scan.io/api?module=stats&action=ethsupply"
Не каждое действие этого контракта здесь существует: те, которым нужны данные, которых в Arc нет, или индекс, которого мы не ведём, отклоняются поимённо. Полную таблицу диспетчеризации и список недоступных действий приводит справочник по APIОткроется в новой вкладке на самом сайте; он генерируется из самого сервиса, поэтому не может разойтись с реальностью так, как может страница вроде этой.
Как читать JSON#
Четыре соглашения порождают все ошибки интеграции, которые стоит называть. Первое — самое дорогое: сумма с 18 знаками не переживает JavaScript-типа Number, поэтому суммы идут по проводу строками и разбирать их нужно как строки.
| Соглашение | Что это значит на проводе |
|---|---|
| Суммы | Объект, а не число: raw (целое строкой), decimals, formatted (точно), usd, symbol. Величины газа и предложения — тоже десятичные строки. Высоты блоков — числа JSON. |
| Регистр | Ключи в snake_case. Адреса и хеши в нижнем регистре, а отображаемая форма стоит рядом в поле checksum. На входе принимается любой регистр. |
| Время | Секунды Unix, никогда не отформатированные заранее. Блоки приходят примерно дважды в секунду, а метки времени имеют разрешение в одну секунду, поэтому полного порядка они не задают — никогда не сортируйте и не разбивайте по ним на страницы. |
| Постраничность | Непрозрачные курсоры в page.next, а не номера страниц. Продолжать ли, говорит page.has_more. |
Зафиксированная история неизменна и кешируется соответственно
Ответ, ключом которого является зафиксированная высота или хеш попавшей в блок транзакции, отдаётся сCache-Control: public, max-age=31536000, immutable. У Arc мгновенная финальность и нет реорганизаций, поэтому это настоящая гарантия, а не вероятностная: кешируйте такие ответы навсегда и вовсе пропускайте запрос.Ошибки#
Отказ — это объект JSON с машиночитаемым code, сообщением, написанным для человека, и необязательным detail. Ветвитесь по code, никогда по тексту сообщения.
curl https://api.arc-scan.io/v1/blocks/999999999999 # 404 # {"error":{"code":"NOT_FOUND","message":"No block at height 999999999999","detail":null}} curl https://api.arc-scan.io/v1/tokens/0x3600000000000000000000000000000000000000/holders # 501 # {"error":{"code":"CAPABILITY_UNAVAILABLE", # "message":"The native gas token has no separate holder list: its balances are account # balances, and indexing them again would double-count every account.", # "detail":{"capability":"holder_index","detail_key":"holdersNativeToken"}}}
| Статус | code | Когда |
|---|---|---|
| 404 | NOT_FOUND | Такого блока, транзакции, записи об адресе или токена нет. |
| 429 | RATE_LIMITED | Слишком много запросов. Несёт Retry-After в секундах. |
| 501 | CAPABILITY_UNAVAILABLE | Данным нужна возможность, которой у этой сети или у этой установки нет. |
| 502 | UPSTREAM_ERROR | Нода ответила, но бесполезно. |
| 503 | INDEX_OVERLOADED | Тяжёлый запрос был отброшен, а не поставлен в очередь. |
| 504 | UPSTREAM_TIMEOUT | Нода не ответила вовремя. |
Читайте оболочку ошибки, а не только статус
Некорректный или выходящий за границы параметр — неразбираемая ссылка на блок,limit выше максимума, отсутствующий обязательный запрос, опечатка в имени поля JSON — возвращается как 400 {"error":{"code":"INVALID_INPUT","message":"limit: Input should be greater than or equal to 1","detail":null}}. code относит ошибку к виду, а message называет поле, из-за которого она возникла, — обычно это быстрее, чем перечитывать URL. 404 здесь означает, что ресурса действительно нет.Ограничения и доступ#
Ни ключа API, ни тарифов, ни регистрации. Запросы учитываются по каждому вызывающему через token bucket, и каждый ответ сообщает, где вы находитесь, — читайте заголовки, а не зашивайте число в код, потому что бюджет является эксплуатационной настройкой, а не опубликованным обещанием.
| Заголовок | Значение |
|---|---|
X-RateLimit-Limit | Размер ведра, по которому учитывался запрос. |
X-RateLimit-Remaining | Сколько в нём осталось токенов. |
Retry-After | Только при 429 или 503: сколько целых секунд подождать перед повтором. |
X-Request-Id | Есть в ответах API. Приводите его, если нужно спросить про конкретный запрос. |
Ещё два потолка реальны, и о них сообщается, а не умалчивается. Запросы логов ограничены максимальным размахом блоков, и запрос сверх диапазона отклоняется с указанием этого максимума в сообщении, а не подрезается молча. Вызовы трассировки и разницы состояния идут на небольшом выделенном пуле с бюджетом по времени и ограничением размера и выставляют truncated: true, а не зависают.
Как читать Arc без нашего индекса
Если вам нужна цепь, а не наш взгляд на неё, у нас есть ещё и публичная точка JSON-RPC только для чтения для основной сети — см. Публичный RPC. Есть и текстовый /llms.txtОткроется в новой вкладке, описывающий, что держит этот обозреватель, — для всего, что читает прозу прежде схемы.