# V3 Custody ## Documentation - [Introduction to V3 Custody](https://docs.v3.finance/introduction.md): Landing page introducing V3 Custody, its MPC-based secure custody for digital assets, key features, and ways to get started with API, web, or mobile. - [Quickstart](https://docs.v3.finance/quickstart.md): Deploy V3 Custody and make your first API call in under 5 minutes to query balances or initiate a transaction. - [Authentication & Permissions](https://docs.v3.finance/authentication.md): Set up secure authentication for API access, including keys, MPC signers, and permission management. - [Error Handling](https://docs.v3.finance/errors.md): Understand and resolve common errors, HTTP codes, and troubleshooting for smooth V3 Custody operations. ## API Reference - [Health check](https://docs.v3.finance/api-reference/get-.md): Публичная проверка живости: аутентификации не требует, к БД не ходит. Годится для мониторинга и как быстрый ответ на вопрос «воркер вообще раскатан?» — но НЕ доказывает доступность D1 - [Landing после magic-link](https://docs.v3.finance/api-reference/get-welcome.md): Callback-страница для нового пользователя после клика по magic-link. Требует активную сессию (cookie) — редиректит на dashboard фронтенда с userId в query. - [Запросить magic-link](https://docs.v3.finance/api-reference/post-api-v1-auth-magic-link.md): Отправляет magic-link на email через Cloudflare Email binding. Войти смогут: существующие пользователи и приглашённые (у кого есть pending invitation) — better-auth hook блокирует регистрацию без приглашения. После клика по ссылке пользователь редиректится на фронтенд (FRONTEND_URL): существующий — /dashboard, новый — /welcome, ошибка — /login. Абсолютные URL, т.к. фронт на другом домене. - [Событие от Wallet Service (TOPUP)](https://docs.v3.finance/api-reference/post-webhooks-wallet.md): Принимает входящие on-chain события. Сейчас обрабатывается только TOPUP. БЕЗ auth/подписи (демо; в проде добавим HMAC). Валидация тела — вручную внутри handler'а (внешний контракт, строгая схема не навязывается). Токен резолвится из реестра по contract address (приоритет) или по коду (fallback с warning'ом); незнакомый токен игнорируется. Зачисление — ledger-проводка topup атомарным batch'ем: address:available ← vault:external. Для основного токена адреса баланс берётся из ledger; для «неосновного» (asset_mismatch) средства учитываются на отдельном ledger-счёте и видны в GET /vaults/{code}/balances. Идемпотентность: unique(network, txHash) и unique(webhookEventId) — дубликат вернёт 200 {duplicate: true}. TRX-события и незнакомые адреса игнорируются (200 {ignored: true}). - [Список сетей](https://docs.v3.finance/api-reference/get-api-v1-networks.md): Глобальный реестр сетей (по coinType asc). Используется UI-пикером при создании Vault'а и регистрации токенов. - [Зарегистрировать сеть](https://docs.v3.finance/api-reference/post-api-v1-networks.md): Добавляет сеть в глобальный реестр. coinType — BIP-44/SLIP-0044 идентификатор, уникален. slug — on-chain имя (lowercase), на него ссылаются Address.network, Token и webhook-матчинг. - [Изменить метаданные сети](https://docs.v3.finance/api-reference/patch-api-v1-networks-id.md): Частичное обновление метаданных сети (admin): name, description, logoUri (логотип), type (тип сети). coinType/code/slug неизменяемы — на них ссылаются адреса, токены и webhook-матчинг. - [Список токенов](https://docs.v3.finance/api-reference/get-api-v1-tokens.md): Глобальный реестр токенов с сетями. Фильтры: ?network= (slug сети), ?enabled=true|false. - [Зарегистрировать токен](https://docs.v3.finance/api-reference/post-api-v1-tokens.md): Добавляет токен в глобальный реестр. Сеть — только из реестра Networks (по networkCode). Уникальность: code глобально, contractAddress в рамках сети, native coin — один на сеть. Для не-native токенов contractAddress обязателен (по нему webhook верифицирует входящие переводы). - [Изменить токен](https://docs.v3.finance/api-reference/patch-api-v1-tokens-id.md): Частичное обновление: symbol, name, logoUri (логотип) и enabled (kill-switch: disabled-токен → переводы отвергаются с TOKEN_NOT_FOUND, webhook игнорирует события, новые политики/vault'ы не могут ссылаться; существующие данные и ledger-счета не трогаются). code/contractAddress/decimals неизменяемы — на них ссылаются ledger, политики и derivation-структуры. - [Курсы токенов к USD (live, публичный)](https://docs.v3.finance/api-reference/get-api-v1-rates.md): Публичный (без auth). Текущие курсы к USD, запрашиваются в моменте (не кэшируются). `?codes=usdt,a7a5` — конкретные токены; без параметра — все enabled-токены реестра. usdRate = USD за 1 единицу токена (decimal-строка) или null, если курс не настроен / источник недоступен. - [Адреса Vault'а](https://docs.v3.finance/api-reference/get-api-v1-vaults-code-addresses.md): Адреса Vault'а (по createdAt desc, keyset-пагинация), обогащённые asset-информацией и decimal-балансом. Для участника — СВОИ (createdById из сессии) + опционально расшаренные (?access); для admin — ВЕСЬ Vault (?userId= сузить до владельца). Сценарии: - все мои usdt-адреса — ?token=usdt - поиск моего адреса — ?search=TQ5k (подстрока в on-chain адресе или label) - [Создать адрес](https://docs.v3.finance/api-reference/post-api-v1-vaults-code-addresses.md): Полный flow создания адреса: 1. Расчёт следующего pathIndex для комбинации сегментов (SQL MAX, retry при конкурентном конфликте) 2. Сборка канонического derivation path 3. evaluatePolicy (action=create_address) — 403 при deny/block, 202 + id заявки при requireApproval (создание ушло на подпись) 4. Wallet Service /wallet/raw_address — получение on-chain адреса 5. Запись Address + синхронная регистрация в tron-events мониторинге; при сбое мониторинга адрес откатывается (всё или ничего) - [Детали адреса](https://docs.v3.finance/api-reference/get-api-v1-vaults-code-addresses-id.md): Полные данные адреса: баланс (raw + decimal), asset-информация, последние 20 исходящих и 20 входящих операций. Полная лента с пагинацией — GET /vaults/{code}/history?addressId=... - [Изменить метаданные адреса](https://docs.v3.finance/api-reference/patch-api-v1-vaults-code-addresses-id.md): Частичное обновление метаданных адреса его ВЛАДЕЛЬЦЕМ: label, description, tags, logoUri (логотип), color, emoji. Правит только владелец (createdById из сессии) — даже admin чужой адрес не меняет (чужой/несуществующий → 404). On-chain данные, баланс и derivation path не затрагиваются. - [Мои папки адресов + доступные мне](https://docs.v3.finance/api-reference/get-api-v1-vaults-code-address-folders.md): Группы, где я менеджер ИЛИ имею грант. Пустой список у нового участника — норма - [Создать папку адресов](https://docs.v3.finance/api-reference/post-api-v1-vaults-code-address-folders.md): Группа адресов — способ выдать доступ сразу к набору адресов одним грантом. Создатель становится менеджером группы - [Папка: адреса + участники](https://docs.v3.finance/api-reference/get-api-v1-vaults-code-address-folders-id.md): Состав группы и выданные на неё гранты одним ответом - [Изменить группу](https://docs.v3.finance/api-reference/patch-api-v1-vaults-code-address-folders-id.md): Название, описание, UI-метаданные. Состав и гранты правятся отдельными ручками. - [Удалить группу](https://docs.v3.finance/api-reference/delete-api-v1-vaults-code-address-folders-id.md): Каскадит members; гранты на группу тоже снимаются. - [Добавить адрес в папку (создатель папки, свой адрес)](https://docs.v3.finance/api-reference/post-api-v1-vaults-code-address-folders-id-members.md): Состав папки меняет ТОЛЬКО её создатель (менеджер), и только СВОИМИ адресами. Второе ограничение — про безопасность, а не про удобство: положив в общую папку адрес, к которому у вас лишь просмотр, вы открыли бы его всем участникам папки мимо его владельца. Папка даёт доступ, но не владение. - [Убрать адрес из группы](https://docs.v3.finance/api-reference/delete-api-v1-vaults-code-address-folders-id-members-addressid.md): Снимает адрес из папки: доступ по грантам НА ПАПКУ к нему прекращается, прямые гранты на сам адрес не затрагиваются. Может создатель папки — и ВСЕГДА владелец адреса: последнее предохранитель, чтобы человек мог изъять свой адрес из чужой папки, не завися от её менеджера. - [Гранты на папку](https://docs.v3.finance/api-reference/get-api-v1-vaults-code-address-folders-id-grants.md): Кто имеет доступ к адресам папки. Владельцы адресов сюда не входят — у них доступ по владению. Каждый элемент содержит `role` — собирать её из флагов на клиенте не нужно. - [Поделиться папкой (создатель/admin)](https://docs.v3.finance/api-reference/post-api-v1-vaults-code-address-folders-id-grants.md): Грант на ПАПКУ (группу адресов): субъект получает права на все адреса папки, включая добавленные позже. Права задаются РОЛЬЮ — `role: viewer|contributor` (как у гранта на адрес). Legacy-флаги `canView`/`canTransfer` ещё принимаются; если пришло и то и другое, роль приоритетнее. ИДЕМПОТЕНТЕН: повтор для той же пары (субъект, папка) меняет права, отозванный грант реактивирует — 409 `GRANT_EXISTS` больше не возвращается. Раньше он возвращался, и клиенту приходилось ловить его, искать грант в списке и слать PATCH — три запроса вместо одного. `canCreateAddress` — отдельное право «заводить НОВЫЕ адреса в эту папку», в роль не входит и по умолчанию не выдаётся: роль описывает доступ к тому, что в папке уже есть. - [Изменить грант папки](https://docs.v3.finance/api-reference/patch-api-v1-vaults-code-address-folders-id-grants-grantid.md): Меняет права уже выданного гранта. Принимает `role` (viewer|contributor) — он задаёт view/transfer целиком; либо точечные legacy-флаги. `canCreateAddress` в роль не входит и меняется отдельно. Ответ содержит `role`. - [Отозвать грант группы](https://docs.v3.finance/api-reference/delete-api-v1-vaults-code-address-folders-id-grants-grantid.md): Soft-revoke: запись сохраняется со статусом revoked для аудита. Действует немедленно. - [Участники папки](https://docs.v3.finance/api-reference/get-api-v1-vaults-code-address-folders-id-participants.md): Список ЛЮДЕЙ с доступом к папке, а не грантов: группы пользователей раскрыты, создатель (менеджер) отдан отдельно. Поле `via` объясняет источник доступа: `direct` — личный грант, отзывается точечно; `user_group` — грант выдан группе, снимается только выходом из неё. `removable` подсказывает, активна ли кнопка «убрать». - [Мои папки адресов + доступные мне](https://docs.v3.finance/api-reference/get-api-v1-vaults-code-address-groups.md): Группы, где я менеджер ИЛИ имею грант. Пустой список у нового участника — норма - [Создать папку адресов](https://docs.v3.finance/api-reference/post-api-v1-vaults-code-address-groups.md): Группа адресов — способ выдать доступ сразу к набору адресов одним грантом. Создатель становится менеджером группы - [Папка: адреса + участники](https://docs.v3.finance/api-reference/get-api-v1-vaults-code-address-groups-id.md): Состав группы и выданные на неё гранты одним ответом - [Изменить группу](https://docs.v3.finance/api-reference/patch-api-v1-vaults-code-address-groups-id.md): Название, описание, UI-метаданные. Состав и гранты правятся отдельными ручками. - [Удалить группу](https://docs.v3.finance/api-reference/delete-api-v1-vaults-code-address-groups-id.md): Каскадит members; гранты на группу тоже снимаются. - [Добавить адрес в папку (создатель папки, свой адрес)](https://docs.v3.finance/api-reference/post-api-v1-vaults-code-address-groups-id-members.md): Состав папки меняет ТОЛЬКО её создатель (менеджер), и только СВОИМИ адресами. Второе ограничение — про безопасность, а не про удобство: положив в общую папку адрес, к которому у вас лишь просмотр, вы открыли бы его всем участникам папки мимо его владельца. Папка даёт доступ, но не владение. - [Убрать адрес из группы](https://docs.v3.finance/api-reference/delete-api-v1-vaults-code-address-groups-id-members-addressid.md): Снимает адрес из папки: доступ по грантам НА ПАПКУ к нему прекращается, прямые гранты на сам адрес не затрагиваются. Может создатель папки — и ВСЕГДА владелец адреса: последнее предохранитель, чтобы человек мог изъять свой адрес из чужой папки, не завися от её менеджера. - [Гранты на папку](https://docs.v3.finance/api-reference/get-api-v1-vaults-code-address-groups-id-grants.md): Кто имеет доступ к адресам папки. Владельцы адресов сюда не входят — у них доступ по владению. Каждый элемент содержит `role` — собирать её из флагов на клиенте не нужно. - [Поделиться папкой (создатель/admin)](https://docs.v3.finance/api-reference/post-api-v1-vaults-code-address-groups-id-grants.md): Грант на ПАПКУ (группу адресов): субъект получает права на все адреса папки, включая добавленные позже. Права задаются РОЛЬЮ — `role: viewer|contributor` (как у гранта на адрес). Legacy-флаги `canView`/`canTransfer` ещё принимаются; если пришло и то и другое, роль приоритетнее. ИДЕМПОТЕНТЕН: повтор для той же пары (субъект, папка) меняет права, отозванный грант реактивирует — 409 `GRANT_EXISTS` больше не возвращается. Раньше он возвращался, и клиенту приходилось ловить его, искать грант в списке и слать PATCH — три запроса вместо одного. `canCreateAddress` — отдельное право «заводить НОВЫЕ адреса в эту папку», в роль не входит и по умолчанию не выдаётся: роль описывает доступ к тому, что в папке уже есть. - [Изменить грант папки](https://docs.v3.finance/api-reference/patch-api-v1-vaults-code-address-groups-id-grants-grantid.md): Меняет права уже выданного гранта. Принимает `role` (viewer|contributor) — он задаёт view/transfer целиком; либо точечные legacy-флаги. `canCreateAddress` в роль не входит и меняется отдельно. Ответ содержит `role`. - [Отозвать грант группы](https://docs.v3.finance/api-reference/delete-api-v1-vaults-code-address-groups-id-grants-grantid.md): Soft-revoke: запись сохраняется со статусом revoked для аудита. Действует немедленно. - [Участники папки](https://docs.v3.finance/api-reference/get-api-v1-vaults-code-address-groups-id-participants.md): Список ЛЮДЕЙ с доступом к папке, а не грантов: группы пользователей раскрыты, создатель (менеджер) отдан отдельно. Поле `via` объясняет источник доступа: `direct` — личный грант, отзывается точечно; `user_group` — грант выдан группе, снимается только выходом из неё. `removable` подсказывает, активна ли кнопка «убрать». - [Список контрагентов](https://docs.v3.finance/api-reference/get-api-v1-vaults-code-counterparties.md): Контрагенты Vault'а (по createdAt desc, keyset-пагинация) со счётчиками адресов и операций. По умолчанию — только активные. - [Создать контрагента](https://docs.v3.finance/api-reference/post-api-v1-vaults-code-counterparties.md): Создаёт контрагента, опционально сразу с адресами. Имя уникально в рамках Vault'а; каждый адрес — уникален в рамках Vault'а (принадлежит максимум одному контрагенту, иначе матчинг неоднозначен). Сети адресов валидируются по реестру Networks. **Ретро-матч**: существующим операциям с этими адресами (у которых counterpartyId ещё NULL) автоматически проставляется контрагент — счётчики в ответе. - [Детали контрагента](https://docs.v3.finance/api-reference/get-api-v1-vaults-code-counterparties-id.md): Контрагент с адресами и счётчиками операций. Сами операции — GET /vaults/{code}/history?counterpartyId=... - [Изменить контрагента](https://docs.v3.finance/api-reference/patch-api-v1-vaults-code-counterparties-id.md): Частичное обновление: name/description/kind/tags/avatarUri/color/emoji. Архивирование — отдельным POST /:id/archive. Гейтится политикой counterparty_update: allow → сразу; requireApproval → заявка (202); deny → 403. - [Архивировать/вернуть контрагента](https://docs.v3.finance/api-reference/post-api-v1-vaults-code-counterparties-id-archive.md): archived=true — архив (перестаёт матчиться на новые операции и недоступен для новых переводов; история сохраняется); false — вернуть. Гейтится политикой counterparty_archive (обе стороны). - [Добавить адрес контрагенту](https://docs.v3.finance/api-reference/post-api-v1-vaults-code-counterparties-id-addresses.md): Добавляет on-chain адрес (уникален в рамках Vault'а — конфликт с другим контрагентом даст 400 с его именем). Выполняет **ретро-матч**: существующие операции с этим адресом (counterpartyId = NULL) привязываются автоматически — счётчики в ответе. - [Убрать адрес у контрагента](https://docs.v3.finance/api-reference/delete-api-v1-vaults-code-counterparties-id-addresses-addrid.md): Удаляет адрес из справочника. Уже привязанные операции НЕ отвязываются (на момент операции адрес принадлежал контрагенту — это исторический факт); новые операции с этим адресом матчиться перестанут. - [Список групп контрагентов](https://docs.v3.finance/api-reference/get-api-v1-vaults-code-counterparty-groups.md): Группы общие на Vault. Используются в белом списке получателей: селектор counterpartyGroup в политике на transfer - [Создать группу контрагентов](https://docs.v3.finance/api-reference/post-api-v1-vaults-code-counterparty-groups.md): Мутация гейтится политикой counterparty_group_create: при требовании подписи вернётся ЗАЯВКА, а не созданная группа - [Детали группы](https://docs.v3.finance/api-reference/get-api-v1-vaults-code-counterparty-groups-id.md): Состав группы — ТЕКУЩИЙ. Белый список по группе проверяет его на момент перевода, а не на момент создания политики - [Изменить группу](https://docs.v3.finance/api-reference/patch-api-v1-vaults-code-counterparty-groups-id.md): Гейтится политикой counterparty_group_update — может вернуть заявку - [Архивировать/вернуть группу](https://docs.v3.finance/api-reference/post-api-v1-vaults-code-counterparty-groups-id-archive.md): Гейтится политикой counterparty_group_archive. Архивная группа перестаёт пропускать переводы в белом списке — ТИХО, без правки политики - [Добавить контрагента в группу](https://docs.v3.finance/api-reference/post-api-v1-vaults-code-counterparty-groups-id-members.md): Гейтится политикой counterparty_group_add. ВНИМАНИЕ: добавление расширяет белый список немедленно — список надёжен настолько, насколько защищён справочник контрагентов - [Убрать контрагента из группы](https://docs.v3.finance/api-reference/delete-api-v1-vaults-code-counterparty-groups-id-members-cpid.md): Гейтится политикой counterparty_group_remove. Платежи этому контрагенту по белому списку группы прекратятся сразу - [Лента заявок](https://docs.v3.finance/api-reference/get-api-v1-vaults-code-approval-requests.md): Заявки, видимые мне (инициатор / одобряющий / admin). Фильтры: ?status=PENDING|APPROVED|REJECTED|CANCELLED, ?action=, ?mine=true (я инициатор), ?pendingMine=true (ждут МОЕГО голоса), ?from/?to (createdAt), ?resolvedFrom/?resolvedTo, ?initiatorId=, ?approverId=, ?decisionPolicyId=, ?targetType=. Каждый элемент обогащён (§21.1): initiator (карточка), У заявок на ПЕРЕВОД (targetType=transfer) приходит блок `transfer`: сумма (raw + amountDecimal), актив, получатель, статус, txHash, адрес-источник. Он нужен, чтобы лента согласований строилась из ОДНОГО источника: до него деньги были только в Transaction, и клиенты держали второй поток (переводы из /history) ради суммы — из-за чего один и тот же перевод показывался как ДВА ожидания. У остальных действий — null. Полная карточка перевода по-прежнему за GET /transfers/:id. decisionPolicyName, approvalsCount/rejectsCount, firstVoteAt/lastVoteAt, resolutionDurationSeconds. - [Создать композитную заявку (цепочка шагов)](https://docs.v3.finance/api-reference/post-api-v1-vaults-code-approval-requests-composite.md): Цепочка counterparty-действий как ЕДИНАЯ сущность с одним флоу одобрения. Каждый шаг гейтится СВОЕЙ политикой; голос approve засчитывается шагам, где голосующий уполномочен; заявка APPROVED, когда каждый шаг набрал свой порог. Reject = вето всей цепочки. Payload шага может ссылаться на результат предыдущего: `"$step:N"` (например, membership на созданных в цепочке контрагента и группу). Все шаги allow/bypass → цепочка применяется сразу (200); любой шаг block/deny → 403 вся цепочка; иначе → заявка (202). При сбое шага в apply — best-effort откат созданного. - [Деталь заявки](https://docs.v3.finance/api-reference/get-api-v1-vaults-code-approval-requests-id.md): Заявка с одобряющими (профильные карточки), полной историей событий (аудит) и инициатором. Видит инициатор / одобряющий / admin. - [Проголосовать по заявке](https://docs.v3.finance/api-reference/post-api-v1-vaults-code-approval-requests-id-approvals.md): Голос одобряющего. reject = вето (заявка REJECTED). Финальный approve (добран порог) применяет мутацию В ЭТОМ ЖЕ запросе (с optimistic-lock: если цель изменилась — REJECTED stale). В ответе финальный статус + resolvedResultId / applyError. - [Отменить заявку (инициатором)](https://docs.v3.finance/api-reference/post-api-v1-vaults-code-approval-requests-id-cancel.md): Инициатор отзывает свою заявку, пока она PENDING → CANCELLED. - [Метаданные операции](https://docs.v3.finance/api-reference/get-api-v1-vaults-code-operations-operationtype-operationid-metadata.md): Плоские метаданные (категория, назначение платежа, теги, ссылки). Не путать с настраиваемыми категориями — те живут в /categories и версионируются - [Задать/обновить метаданные операции](https://docs.v3.finance/api-reference/patch-api-v1-vaults-code-operations-operationtype-operationid-metadata.md): Upsert: paymentPurpose, category (валидируемый код), tags, description, внешние референсы и бизнес-связи (dealId/invoiceId/orderId/settlementId/obligationId). Каждое изменение инкрементит version. - [История статусов операции (§9)](https://docs.v3.finance/api-reference/get-api-v1-vaults-code-operations-operationtype-operationid-status-history.md): Хронология переходов статуса (OperationStatusHistory). Для операций, созданных до внедрения — одна legacy-baseline запись. - [Связи операции](https://docs.v3.finance/api-reference/get-api-v1-vaults-code-operations-operationtype-operationid-relations.md): Связи операции с другими: refund, reversal, correction, replacement. Направление важно — операция может быть и источником, и целью связи - [Список связей операций](https://docs.v3.finance/api-reference/get-api-v1-vaults-code-operation-relations.md): Связи между операциями Vault'а: refund, reversal, correction, replacement. Показывает обе стороны — операция может быть и источником, и целью связи. Для связей КОНКРЕТНОЙ операции есть /operations/{type}/{id}/relations - [Создать связь операций](https://docs.v3.finance/api-reference/post-api-v1-vaults-code-operation-relations.md): Явная связь refund/reversal/correction/replacement (§11: встречный платёж НЕ считается возвратом автоматически). Обе операции — в этом Vault'е и доступны инициатору. Самоссылка запрещена. relatedAmountRaw (частичный возврат) требует tokenId и валидируется по токену операции. Связи не удаляются физически. - [Участники Vault'а, видимые мне (для выбора грантополучателя)](https://docs.v3.finance/api-reference/get-api-v1-vaults-code-members.md): Видимость задаётся грантами (/visibility-grants). Дефолт — только я; admin — все. PII-минимум (без email). Поиск по name/username. - [Точный резолв участника по username](https://docs.v3.finance/api-reference/get-api-v1-vaults-code-members-resolve.md): Share-by-handle: вернёт участника, только если он мне ВИДИМ (грант видимости). Нельзя пробить существование невидимого username. email не отдаётся. - [Группы пользователей Vault'а (для гранта на группу)](https://docs.v3.finance/api-reference/get-api-v1-vaults-code-user-groups.md): Read-only список PolicyGroup: id, name, memberCount. Управление — admin-ручки. - [Члены группы юзеров (видимые мне) + total](https://docs.v3.finance/api-reference/get-api-v1-vaults-code-user-groups-id-members.md): Чтобы владелец осознавал, КОМУ реально открывает доступ, выдавая грант на группу. total — реальный размер; items — видимые мне (грант видимости). - [Деталь группы юзеров (описание, политики, видимые члены)](https://docs.v3.finance/api-reference/get-api-v1-vaults-code-user-groups-id.md): Read-only. Политики группы показываются участнику как справка (правит их admin через /policy-groups). Члены — только видимые мне (грант видимости). - [Участник (видимый мне) + его группы](https://docs.v3.finance/api-reference/get-api-v1-vaults-code-members-id.md): Только если участник мне ВИДИМ (грант видимости). groups — PolicyGroup'ы Vault'а. - [Кому расшарен мой адрес](https://docs.v3.finance/api-reference/get-api-v1-vaults-code-addresses-id-shares.md): Активные гранты на адрес. Владелец (createdById) и admin имеют полный доступ всегда и в списке грантов НЕ фигурируют — грант только расширяет - [Выдать доступ к адресу (владелец/admin)](https://docs.v3.finance/api-reference/post-api-v1-vaults-code-addresses-id-shares.md): Грант на КОНКРЕТНЫЙ адрес. Права флагами в одной записи: canView, canTransfer, canCreateAddress. Идемпотентен: повторная выдача тому же субъекту обновляет права и реактивирует отозванный грант — отдельного «изменить» не нужно. Субъект полиморфен: {subjectType:"user", subjectUserId} или {subjectType:"group", subjectGroupId} (PolicyGroup — членство резолвится ТЕКУЩЕЕ, не снапшот). Кому можно выдать — ограничено грантом видимости: «кого видишь = кому можешь дать доступ». Себе и владельцу адреса выдать нельзя. ИДЕМПОТЕНТЕН: повторная выдача тому же получателю меняет роль, отозванный грант реактивирует. 409 больше не возвращается — поведение выровнено с грантами видимости и категорий. ПАКЕТ: `subjects[]` — несколько получателей за раз. Каждый обрабатывается независимо, результат по каждому в `results[]`: ошибка по одному (например, он вам не видим) не отменяет остальных. Уведомление шлётся только при РЕАЛЬНОМ изменении — повтор с той же ролью пуш не порождает - [Изменить права гранта](https://docs.v3.finance/api-reference/patch-api-v1-vaults-code-addresses-id-shares-shareid.md): Меняет флаги прав. Эквивалент повторного POST с теми же субъектом и объектом — оставлено для явности намерения - [Отозвать доступ (soft)](https://docs.v3.finance/api-reference/delete-api-v1-vaults-code-addresses-id-shares-shareid.md): Soft-revoke: запись остаётся со status=revoked, revokedAt, revokedById — аудит «когда и кто отозвал» сохраняется. Действует немедленно - [Адреса, расшаренные мне (прямые гранты на адрес)](https://docs.v3.finance/api-reference/get-api-v1-vaults-code-shared-with-me.md): Только ПРЯМЫЕ гранты на адрес. Доступ через группу адресов сюда не попадает — см. /address-groups. Для «всё доступное мне» используйте /addresses?access=shared - [Мои выданные гранты](https://docs.v3.finance/api-reference/get-api-v1-vaults-code-shared-by-me.md): Обратная сторона /shared-with-me: что я открыл другим — и адреса, и ПАПКИ. Фильтр по targetType='address' был здесь с тех пор, когда папки ещё не были расшариваемыми: после слияния папки с группой адресов он молча прятал половину выданного доступа - [Участники адреса](https://docs.v3.finance/api-reference/get-api-v1-vaults-code-addresses-id-participants.md): Список ЛЮДЕЙ с доступом, а не грантов: группы пользователей раскрыты, доступ через папку учтён, владелец отдан отдельно. Это то, что рисует экран «Участники». Поле `via` объясняет ИСТОЧНИК доступа и тем самым способ его убрать: прямой грант отзывается точечно, доступ от группы пользователей — только выходом из группы. `removable` подсказывает, доступна ли кнопка «убрать». Права суммируются: доступ и напрямую, и через группу даёт максимум. - [Отказаться от доступа, который мне выдали](https://docs.v3.finance/api-reference/delete-api-v1-vaults-code-shared-with-me-grantid.md): Получатель убирает доступ у СЕБЯ, не спрашивая владельца. В iCloud это «Remove Me»: мне расшарили лишнее — я убираю это из своего списка. Работает только для ПРЯМОГО гранта лично мне. Доступ, полученный через группу пользователей, так снять нельзя — он у всей группы; ответ **409 `ACCESS_VIA_GROUP`** с id и именем группы, чтобы UI объяснил «доступ у вас от группы Казначеи, выйдите из неё». Отзыв soft: запись сохраняется с revokedAt/revokedById. Владелец при желании может выдать доступ снова. - [Гранты видимости Vault'а (admin)](https://docs.v3.finance/api-reference/get-api-v1-vaults-code-visibility-grants.md): Активные гранты с карточками субъекта и целевой группы. ?subjectGroupId= / ?subjectUserId= — что открыто конкретному субъекту (для карточки группы или пользователя). - [Открыть видимость участников (admin)](https://docs.v3.finance/api-reference/post-api-v1-vaults-code-visibility-grants.md): Кому (subjectType user|group) и кого он видит (scope self|group|vault). scope="self" для group-субъекта — участники этой же группы; для user-субъекта — участники всех его групп. scope="group" требует targetGroupId. Повторный грант той же пары реактивирует отозванный. - [Отозвать грант видимости (admin)](https://docs.v3.finance/api-reference/delete-api-v1-vaults-code-visibility-grants-id.md): Soft-revoke: строка остаётся для аудита, но перестаёт действовать сразу для новых запросов. - [Список категорий Vault'а](https://docs.v3.finance/api-reference/get-api-v1-vaults-code-operation-categories.md): Доступно ЛЮБОМУ участнику Vault'а — это справочник для конструктора отчётов и фильтров (по нему выбирают categoryKey, groupByField, metricField, собирают categoryField). Виден ВЕСЬ список: `viewScope` ограничивает доступ к ЗНАЧЕНИЯМ на операциях, а не к схеме — при дефолтном owner_only человек законно размечает своими категориями свои операции и строит по ним отчёты. Гранты и аппруверы (конфиг доступа) не-админу не отдаются. Для ФОРМЫ РАЗМЕТКИ конкретной операции нужна другая ручка — /operations/{type}/{id}/categories/available: она учитывает права на адресе операции, а этот справочник про Vault в целом. Включает архивные (фильтр в query): отчёт за прошлый период может ссылаться на категорию, которую уже архивировали. - [Создать категорию разметки](https://docs.v3.finance/api-reference/post-api-v1-vaults-code-operation-categories.md): Админ создаёт тип разметки (категорию) с типизированными полями. key категории/полей — стабильные слаги (иммутабельны). Доступ и аппруверы настраиваются отдельными ручками. - [Категория (поля; гранты и аппруверы — админу)](https://docs.v3.finance/api-reference/get-api-v1-vaults-code-operation-categories-id.md): Участнику — определение категории и её поля (для формы фильтров и конструктора отчётов); гранты и аппруверы вырезаются. Админу — полная конфигурация. key категории и key/type полей ИММУТАБЕЛЬНЫ после создания: на них ссылаются значения, версии и отчёты - [Изменить настройки категории](https://docs.v3.finance/api-reference/patch-api-v1-vaults-code-operation-categories-id.md): name/описание/оформление/скоупы/approval/archived. version++. key/поля — отдельно. - [Добавить поле в категорию](https://docs.v3.finance/api-reference/post-api-v1-vaults-code-operation-categories-id-fields.md): key и type поля неизменяемы после создания. Поле с историей нельзя удалить — только архивировать, иначе прошлые значения осиротеют - [Изменить поле категории](https://docs.v3.finance/api-reference/patch-api-v1-vaults-code-operation-categories-id-fields-fid.md): label/required/options(добавить)/unit/helpText/sensitive/order/archived. key и type — иммутабельны. - [Выдать доступ к категории](https://docs.v3.finance/api-reference/post-api-v1-vaults-code-operation-categories-id-grants.md): Единая форма гранта (как у адресов и видимости): субъект user|group + права флагами canView/canAssign/canEdit в ОДНОЙ записи. Повторный вызов той же пары (категория, субъект) обновляет права и реактивирует отозванный грант. Субъект `role` убран — «всем участникам» задаётся scope категории. - [Отозвать доступ к категории](https://docs.v3.finance/api-reference/delete-api-v1-vaults-code-operation-categories-id-grants-gid.md): Soft-revoke (как у остальных грантов): запись остаётся для аудита, действие прекращается сразу. - [Добавить аппрувера категории (D4)](https://docs.v3.finance/api-reference/post-api-v1-vaults-code-operation-categories-id-approvers.md): kind=user(userId) | group(policyGroupId). Порог/флаги — в PATCH категории. - [Снять аппрувера категории](https://docs.v3.finance/api-reference/delete-api-v1-vaults-code-operation-categories-id-approvers-aid.md): Аппруверы категории — объектное требование (D4): правка значений ЭТОЙ категории требует их подписи независимо от роли правящего - [Категории операции (видимые вызывающему)](https://docs.v3.finance/api-reference/get-api-v1-vaults-code-operations-type-id-categories.md): Присвоенные категории со значениями. sensitive-поля РЕДАКТИРУЮТСЯ под доступ: значение приходит null, а ключ попадает в redactedFields — показывайте «скрыто», а не пустоту - [Присвоить категорию операции](https://docs.v3.finance/api-reference/post-api-v1-vaults-code-operations-type-id-categories.md): Требует capability assign. Обязательные поля — сразу (D3). Если approvalScope категории = assign_and_edit → запись уходит в заявку (202). - [Категории, доступные вызывающему для присвоения операции](https://docs.v3.finance/api-reference/get-api-v1-vaults-code-operations-type-id-categories-available.md): Именно эту ручку используйте для формы разметки, а не общий список категорий: она учитывает гранты и доступ к адресу операции - [Изменить значения назначения (новая версия)](https://docs.v3.finance/api-reference/patch-api-v1-vaults-code-operations-type-id-categories-assignmentid.md): Патч значений (мердж; null очищает). Требует capability edit. Если approvalScope ∈ {edit, assign_and_edit} → заявка (202, D4) с optimistic-lock. - [Снять категорию с операции (soft)](https://docs.v3.finance/api-reference/delete-api-v1-vaults-code-operations-type-id-categories-assignmentid.md): status=removed + версия-снапшот action=removed. Требует edit. История сохраняется. - [История версий назначения](https://docs.v3.finance/api-reference/get-api-v1-vaults-code-operations-type-id-categories-assignmentid-versions.md): Append-only: каждое изменение значений создаёт версию-снапшот. Отвечает на «кто и когда поменял разметку» - [Снапшот версии назначения](https://docs.v3.finance/api-reference/get-api-v1-vaults-code-operations-type-id-categories-assignmentid-versions-version.md): Полные значения на момент этой версии — вместе с версией схемы категории - [Counterparty Activity Statement (§15)](https://docs.v3.finance/api-reference/get-api-v1-vaults-code-reports-counterparty_activity.md): Интервал: from inclusive, to exclusive; timezone — IANA; decimal — строки. Scope: user — только свои операции; admin — Vault-wide (+?userId=). - [Counterparty Group Activity Report (§16)](https://docs.v3.finance/api-reference/get-api-v1-vaults-code-reports-counterparty_group_activity.md): Интервал: from inclusive, to exclusive; timezone — IANA; decimal — строки. Scope: user — только свои операции; admin — Vault-wide (+?userId=). - [Transaction Activity Report (§17)](https://docs.v3.finance/api-reference/get-api-v1-vaults-code-reports-transaction_activity.md): Интервал: from inclusive, to exclusive; timezone — IANA; decimal — строки. Scope: user — только свои операции; admin — Vault-wide (+?userId=). - [Asset Movement Report (§18, tokenId обязателен)](https://docs.v3.finance/api-reference/get-api-v1-vaults-code-reports-asset_movement.md): Интервал: from inclusive, to exclusive; timezone — IANA; decimal — строки. Scope: user — только свои операции; admin — Vault-wide (+?userId=). - [Address Activity Report (§19, addressId XOR folderId)](https://docs.v3.finance/api-reference/get-api-v1-vaults-code-reports-address_activity.md): Интервал: from inclusive, to exclusive; timezone — IANA; decimal — строки. Scope: user — только свои операции; admin — Vault-wide (+?userId=). - [Account Statement (§14): opening/closing из ledger + reconciliation](https://docs.v3.finance/api-reference/get-api-v1-vaults-code-reports-account_statement.md): Интервал: from inclusive, to exclusive; timezone — IANA; decimal — строки. Scope: user — только свои операции; admin — Vault-wide (+?userId=). - [Operations Exceptions Report (§22): незавершённые/неуспешные + age buckets](https://docs.v3.finance/api-reference/get-api-v1-vaults-code-reports-operations_exceptions.md): Интервал: from inclusive, to exclusive; timezone — IANA; decimal — строки. Scope: user — только свои операции; admin — Vault-wide (+?userId=). - [Approval Activity Report (§21)](https://docs.v3.finance/api-reference/get-api-v1-vaults-code-reports-approval_activity.md): Интервал: from inclusive, to exclusive; timezone — IANA; decimal — строки. Scope: user — только свои операции; admin — Vault-wide (+?userId=). - [Balance Position Report (§20): позиция на момент at](https://docs.v3.finance/api-reference/get-api-v1-vaults-code-reports-balance_position.md): Считается из ledger, а не из текущих балансов — поэтому цифра за прошлый период не «плывёт» при последующих операциях - [Единый отчёт (?type=…)](https://docs.v3.finance/api-reference/get-api-v1-vaults-code-reports.md): Один endpoint на все отчёты: тип — параметром `type`, фильтры — общие query-параметры. Обязательные для типа параметры валидируются: counterparty-activity → counterpartyId; asset-movement → tokenId; address-activity → addressId|folderId; balance-position → без from/to (момент — ?at=). Ошибки — спековый формат {error:{code,message,details}}. - [Drill-down операций отчёта (§26)](https://docs.v3.finance/api-reference/post-api-v1-vaults-code-reports-query-operations.md): Раскрытие любой агрегированной цифры до операций. filters — общие фильтры отчёта (включая categoryKeys и categoryField); drilldown — уточнение (direction/periodStart/counterpartyAddressId/ownAddressId/status/category/tokenId/categoryField). `drilldown.categoryField="ticker:EUR"` раскрывает группу отчёта по полю категории; при совпадении ключа уточнение из клика перекрывает фильтр отчёта. При snapshotId список строится из манифеста снапшота, не из live. - [Аналитика по полям категории](https://docs.v3.finance/api-reference/get-api-v1-vaults-code-reports-category_analytics.md): Группировка операций по значению поля (groupByField) и/или численная агрегация числового поля (metricField + agg=sum|avg|min|max|median|count), decimal-safe. Учитываются операции с активным назначением categoryKey. Область — стандартный report-scope (свои операции / admin — весь Vault). ДЕНЬГИ. Поле типа `currency` хранит только число; его валюта лежит в соседнем поле категории. Если админ ОБЪЯВИЛ связку (`OperationCategoryField.currencyFieldKey`), отчёт разложит сумму по тикеру САМ: `metric.value` = null, числа — в `metric.byCurrency` ({"EUR":"1250.25","USD":"300.75"}), в группах — `metricByCurrency`. Разложение работает и внутри groupByField: разрез по методу оплаты + разные валюты внутри каждого метода — законная комбинация. Общий итог в этом случае не возвращается вовсе: складывать EUR с USD нельзя, и раз схема это знает, отчёт не полагается на то, что его правильно собрали. Связка НЕ объявлена — метрика считается как обычное число (`value` заполнен, `byCurrency` = null). Тогда разрез по тикеру надо задать самому через groupByField, иначе валюты смешаются. Суммы — decimal-строки (никакого float). Хвостовые нули нормализуются ("1200.00" → "1200"): формат под валюту делает клиент. - [Журнал double-entry ledger (§13.1, read-only)](https://docs.v3.finance/api-reference/get-api-v1-vaults-code-ledger-entries.md): Immutable записи с postings (сумма постингов entry = 0). user видит только entries, затрагивающие его адреса; admin — весь Vault. Сортировка postedAt DESC, id DESC; keyset-пагинация. - [Балансы на момент времени (§13.2)](https://docs.v3.finance/api-reference/get-api-v1-vaults-code-balances-as-of.md): Рассчитывается из ledger postings с postedAt <= at. owned balance = available + reserved (reserved — не расход до подтверждения). user — только свои адреса. - [Список снапшотов](https://docs.v3.finance/api-reference/get-api-v1-vaults-code-report-snapshots.md): Снапшот фиксирует данные отчёта с хешем и манифестом: повторный просмотр даёт ТЕ ЖЕ цифры, даже если операции с тех пор изменились. Экспорт делается из снапшота, а не из живого запроса - [Создать снапшот отчёта (§27)](https://docs.v3.finance/api-reference/post-api-v1-vaults-code-report-snapshots.md): Формирует отчёт, фиксирует dataCutoff, сохраняет result + манифест операций + canonical sha256. Снапшот immutable: не меняется при ретро-матче, переименованиях и изменении курса. Результат > ~900KB → REPORT_PERIOD_TOO_LARGE (сузьте фильтры). - [Снапшот (с результатом)](https://docs.v3.finance/api-reference/get-api-v1-vaults-code-report-snapshots-id.md): Метаданные, манифест и сам результат. Хеш позволяет убедиться, что содержимое не менялось с момента фиксации - [Soft-delete снапшота (метаданные/аудит не удаляются)](https://docs.v3.finance/api-reference/delete-api-v1-vaults-code-report-snapshots-id.md): Снимает снапшот из выдачи, но сохраняет аудиторский след: кто и когда фиксировал. Сделанные экспорты остаются — это самостоятельные файлы - [Экспорт снапшота (§28)](https://docs.v3.finance/api-reference/post-api-v1-vaults-code-report-snapshots-snapshotid-exports.md): Строится ИЗ снапшота (не live). Форматы: json, csv (плоский реестр операций). xlsx/pdf — контракт зарезервирован, пока REPORT_UNSUPPORTED_FORMAT (добавим отдельной итерацией). - [Статус экспорта](https://docs.v3.finance/api-reference/get-api-v1-vaults-code-report-exports-id.md): Готовность файла. Экспорт делается ИЗ СНАПШОТА, поэтому его содержимое не зависит от того, что происходило с операциями после фиксации - [Скачать файл экспорта](https://docs.v3.finance/api-reference/get-api-v1-vaults-code-report-exports-id-download.md): Отдаёт файл (JSON/CSV). Ответ НЕ в JSON-конверте — это поток данных, а не API-ответ; ошибки при этом приходят обычным конвертом - [Шаблоны: мои + shared](https://docs.v3.finance/api-reference/get-api-v1-vaults-code-report-templates.md): Сохранённые наборы параметров отчёта. shared-шаблоны видны всем участникам Vault'а, менять их может только admin - [Создать шаблон отчёта (§29)](https://docs.v3.finance/api-reference/post-api-v1-vaults-code-report-templates.md): Сохраняет набор параметров отчёта под именем. isShared=true делает шаблон общим для Vault'а (только admin). ВАЖНО: shared-шаблон НЕ расширяет права — scope пересчитывается под вызывающего при каждом запуске, поэтому двое увидят по нему разные данные. relativePeriod {unit:"week",offset:-1} — относительный период. - [Шаблон](https://docs.v3.finance/api-reference/get-api-v1-vaults-code-report-templates-id.md): Параметры шаблона. Запуск — POST /report-templates/{id}/run - [Изменить шаблон (владелец; shared — admin)](https://docs.v3.finance/api-reference/patch-api-v1-vaults-code-report-templates-id.md): Свой шаблон правит владелец; shared — только admin, потому что им пользуются остальные - [Удалить шаблон](https://docs.v3.finance/api-reference/delete-api-v1-vaults-code-report-templates-id.md): Уже созданные по шаблону снапшоты и экспорты остаются - [Запустить шаблон (live-отчёт)](https://docs.v3.finance/api-reference/post-api-v1-vaults-code-report-templates-id-run.md): Разрешает relativePeriod → конкретные даты и строит отчёт. Permissions пересчитываются на КАЖДЫЙ запуск (shared-шаблон не расширяет права запускающего). - [Единая лента операций](https://docs.v3.finance/api-reference/get-api-v1-vaults-code-history.md): МОЯ активность в Vault'е одной лентой (мои переводы + депозиты на мои адреса), по (createdAt, id) desc, keyset-пагинация. userId — из сессии. Сценарии: - моя лента — без параметров - мои поступления за март — ?direction=in&from=2026-03-01&to=2026-04-01 - мои зависшие переводы — ?direction=out&status=pending - ждут МОЕГО одобрения (чужие переводы) — ?awaitingMyApproval=true - движения по моему адресу — ?addressId=... или папке — ?folderId=... - по группе контрагентов — ?counterpartyGroupId=..., по адресу контрагента — ?counterpartyAddressId=... - только внешние/внутренние — ?flowType=external|internal - по категории/назначению из метаданных — ?category=... / ?paymentPurpose=... Каждый элемент обогащён reporting-полями (§7): operationType, flowType, usdRate/usdValue (exact-снапшот), metadata. Форма элемента зависит от direction: out несёт статус/жизненный цикл, in — свершившийся факт из webhook. - [Отправить перевод](https://docs.v3.finance/api-reference/post-api-v1-vaults-code-transfers.md): Полный flow исходящего transfer'а (демо-инвариант: успешный broadcast = confirmed): 1. Резолв fromAddress, токена (network match), конвертация amount по decimals 2. Balance check (raw units) 3. evaluatePolicy (action=transfer) — 403 при deny/block 4. Запись + ledger-проводка reserve (available → reserved, атомарный batch с guard'ом достаточности) — средства блокируются ДЛЯ ОБЕИХ веток 5. **allow** → исполнение сразу: GasStation → 2s → broadcast → confirm | release+failed → ответ 201 6. **requireApproval** → status=awaiting_approval, ответ **202**; дальше — голоса через POST /transfers/{id}/approvals, финальный approve исполняет перевод **Идемпотентность:** передавайте `idempotencyKey` (уникальный на каждую попытку перевода) — запись резервирует ключ и средства ДО broadcast; повторный запрос с тем же ключом вернёт 200 с существующей транзакцией вместо второго перевода. Резерв атомарен (конкурентные запросы не уведут баланс в минус); после failed/rejected retry — с новым ключом. - [Проголосовать по переводу](https://docs.v3.finance/api-reference/post-api-v1-vaults-code-transfers-id-approvals.md): Голос члена approver-группы по переводу в статусе awaiting_approval. Правила: голосующий — член approver-группы перевода; инициатор не голосует за свой перевод; один голос на человека. - **reject = вето**: перевод сразу rejected, средства возвращаются (release) - **approve**: при достижении порога перевод исполняется В ЭТОМ ЖЕ запросе (gas → broadcast, ~10 сек) — в ответе будет финальный статус confirmed/failed. Если исполнение упало — средства уже возвращены, детали в executionError. Список «ждут моего одобрения»: GET /history?pendingApproverId= - [Отменить перевод (инициатором)](https://docs.v3.finance/api-reference/post-api-v1-vaults-code-transfers-id-cancel.md): Инициатор отзывает свой перевод, пока тот ждёт одобрения (awaiting_approval). Перевод → rejected, зарезервированные средства возвращаются (release). Разрывает «застревание», если одобряющие бездействуют. После одобрения/исполнения отменить нельзя. - [Детали перевода](https://docs.v3.finance/api-reference/get-api-v1-vaults-code-transfers-id.md): Полные данные исходящего перевода: инициатор, адрес отправителя, decimal-сумма, contractAddress токена, решение политики. - [Сеть одобрений (approvers / подопечные)](https://docs.v3.finance/api-reference/get-api-v1-vaults-code-approval-relations.md): Две стороны моих approval-отношений в этом Vault'е, выведенные из РЕАЛЬНЫХ переводов (снапшотов одобряющих), а не из конфига политик: - **approvers** — кто подтверждает МОИ переводы (люди из снапшотов одобряющих на переводах, где я инициатор) - **wards** — мои «подопечные»: инициаторы переводов, где Я назначен одобряющим У каждого — профильная карточка + счётчики: всего общих операций и сколько из них сейчас ждут одобрения. Пусто, пока таких операций не было. `?action=` сужает до одного действия (`transfer`, `create_address`, `counterparty_create`, `category_edit`, …). Без него — ВСЕ действия, и рядом приходит `byAction[]`: разбивка «кто что подписывает». Раньше здесь был зашит только `transfer`, из-за чего нельзя было узнать, кто подписывает создание адреса, хотя данные для этого есть. - [Детали поступления](https://docs.v3.finance/api-reference/get-api-v1-vaults-code-deposits-id.md): Полные данные входящего поступления (создано webhook'ом Wallet Service): decimal-сумма, символ токена, адрес-получатель. amlStatus/amlDetails — placeholder до появления automation engine. - [Список Vault'ов](https://docs.v3.finance/api-reference/get-api-v1-vaults.md): Все Vault'ы, отсортированы по createdAt desc. Каждый — с подключёнными сетями и агрегированными счётчиками (группы, инвайты, политики, члены). - [Создать Vault](https://docs.v3.finance/api-reference/post-api-v1-vaults.md): Создаёт Vault с полной derivation-структурой одним запросом. RouteMap обязан содержать спец-ключ "network" (его варианты upsert'ятся в глобальный реестр Network по coinType). Остальные сегменты становятся Route'ами: order нормализуется от 0 в порядке исходных значений. Vault создаётся в статусе draft (lockedAt = null). D1 не поддерживает транзакции — при частичном сбое выполняется best-effort cleanup. - [Детали Vault](https://docs.v3.finance/api-reference/get-api-v1-vaults-code.md): Полная конфигурация Vault'а: networks (по coinType asc) и routes (по order asc) со всеми вариантами (по pathId asc), включая disabled. - [Группы политик Vault'а](https://docs.v3.finance/api-reference/get-api-v1-vaults-code-policy-groups.md): Все PolicyGroup Vault'а (по createdAt asc) со счётчиками политик и членов. - [Все политики Vault'а (плоско)](https://docs.v3.finance/api-reference/get-api-v1-vaults-code-policies.md): Политики всех групп Vault'а одним списком с owner-группой — для обзора «что вообще действует в этом Vault'е» без обхода групп. Keyset-пагинация. - [Инвайты Vault'а](https://docs.v3.finance/api-reference/get-api-v1-vaults-code-invitations.md): Все приглашения Vault'а (по createdAt desc). Token в листинге НЕ отдаётся (защита от утечки через скриншоты/логи) — только в GET /invitations/:id. - [Балансы: Vault / пользователь / адрес](https://docs.v3.finance/api-reference/get-api-v1-vaults-code-balances.md): Единый endpoint балансов. Баланс — агрегация ledger-счетов (available — можно тратить; reserved — заблокировано pending-переводами, но ещё принадлежит владельцу). Балансы — денормализация double-entry журнала, обновляются атомарно с проводками. ИЗОЛЯЦИЯ: user видит баланс ТОЛЬКО по своим адресам; admin — по всему Vault'у. Фильтры: ?addressId= (свой адрес), ?token=, ?summary=true (только totals, для дашборда), ?purpose= (фильтрует список счетов; totals всегда с разбивкой available/reserved). Vault-level счета (external/adjustment) в totals не входят. - [Собрать derivation path](https://docs.v3.finance/api-reference/post-api-v1-vaults-code-derivation-path-build.md): Собирает канонический derivation path (m/44/{coinType}/{seg0}/...) из значений сегментов. Валидирует: сеть подключена к Vault, все Route.code присутствуют, static-варианты существуют и enabled, dynamic-значения — integer в [0, 2^31-1]. - [Разобрать derivation path](https://docs.v3.finance/api-reference/post-api-v1-vaults-code-derivation-path-parse.md): Разбирает derivation path обратно в компоненты: сеть + значение каждого route (для static — с найденным вариантом, disabled тоже распознаются). Ошибка если префикс не m/44/, coinType не подключён к Vault или число сегментов не совпадает со структурой. - [Создать группу политик](https://docs.v3.finance/api-reference/post-api-v1-policy-groups.md): Создаёт PolicyGroup внутри существующего Vault. Пользователь может состоять в нескольких группах одного Vault — политики объединяются, deny из любой группы приоритетнее. Code уникален в рамках Vault. - [Детали группы](https://docs.v3.finance/api-reference/get-api-v1-policy-groups-id.md): Группа с кратким списком политик и всеми членами. - [Изменить группу политик (admin)](https://docs.v3.finance/api-reference/patch-api-v1-policy-groups-id.md): Частичное обновление: name, description, UI-метаданные (logoUri/color/emoji; null — очистить). code и vaultId неизменяемы — на code ссылаются селекторы actorRole.groupCodes. - [Политики группы](https://docs.v3.finance/api-reference/get-api-v1-policy-groups-id-policies.md): Список политик группы для table view — все поля политики без rules, но со счётчиком rules. - [Добавить пользователя в группу](https://docs.v3.finance/api-reference/post-api-v1-policy-groups-id-members.md): Создаёт PolicyGroupMembership. User-модель для членства не обязательна — userId может быть произвольной строкой (используется и для сервисов). - [Убрать пользователя из группы](https://docs.v3.finance/api-reference/delete-api-v1-policy-groups-id-members-membershipid.md): Удаляет членство (membershipId — из GET /users/:userId/policy-groups или GET /policy-groups/:id). Пользователь теряет политики группы немедленно; помни про default-deny — без allow-политик действия будут запрещены. - [Все права группы: политики + гранты (admin)](https://docs.v3.finance/api-reference/get-api-v1-policy-groups-id-access.md): policies — что группе разрешено делать (принадлежат группе). addressGrants / visibilityGrants / categoryGrants — к чему у группы есть доступ (группа указана субъектом). Только активные гранты. - [Список политик Vault'а (admin)](https://docs.v3.finance/api-reference/get-api-v1-policies.md): Плоский список с фильтрами. vaultId обязателен (политики живут в группах Vault'а). Сортировка: группа → код. Для конструктора правил используйте GET /policies/:id (с rules и селекторами). - [Создать политику](https://docs.v3.finance/api-reference/post-api-v1-policies.md): Создаёт Policy с rules и selectors одним nested write. Валидация: effect=block требует blockReason; одобрение задаётся approval{} + approvers список approvers (userId) + approvalThreshold (1..число approvers); типы селекторов должны быть валидны для actionType; signers — только в require-rules, максимум 1 на политику. Семантика применения: exclude (любой совпал) → политика пропускается; require (все должны совпасть); include (хотя бы один, или их нет) → применяется. - [Детали политики](https://docs.v3.finance/api-reference/get-api-v1-policies-id.md): Политика со всеми rules и selectors, owner-группой и approver-группой. - [Изменить политику](https://docs.v3.finance/api-reference/patch-api-v1-policies-id.md): Частичное обновление (admin): name, description, enabled (kill-switch — disabled-политика не участвует в evaluate; помни про default-deny), approvers/approvalThreshold/adminBypass/allowInitiatorApproval (у allow с approval{}), и **rules** — правила заменяются ЦЕЛИКОМ и валидируются против текущего actionType (типы селекторов, asset-коды из реестра). actionType/effect неизменяемы: их смена = новая политика (старую выключают enabled=false). Правки не влияют на уже созданные переводы/заявки (у них снапшот). - [История версий политики](https://docs.v3.finance/api-reference/get-api-v1-policies-id-versions.md): Append-only редакции политики. Каждое изменение (включая правку лимитов и одобряющих) порождает версию со снапшотом решающей части: effect, condition, approval, limits, approvers. `reason`: created — при создании; updated — при правке; backfill — версия собрана миграцией 0041 из текущего состояния и НЕ обязана совпадать с той, что принимала более старые решения. Решение ссылается на версию полем `decisionPolicyVersionId`; у решений старше Ф4 оно null — версия неизвестна. - [Оценить запрос политиками](https://docs.v3.finance/api-reference/post-api-v1-evaluate.md): Ядро policy engine (deny-overrides): 1. Собираются все политики пользователя в Vault (через членства в группах) 2. Фильтр: enabled=true и actionType = action 3. Применимость: одно булево дерево condition (and/or/not/лист). condition=null → политика применима всегда 4. Резолюция (Ф2): block → нарушенный лимит (отказ или эскалация в подпись) → требования подписи → allow → deny (default-deny). Требования СОБИРАЮТСЯ со всех применимых политик (requirements[]), а не выбирается одно с максимальным порогом — так выражается «CFO И комплаенс» Вызывается внутренне из createAddress/createTransaction, но доступен и напрямую — для dry-run проверок из UI. - [Создать приглашение](https://docs.v3.finance/api-reference/post-api-v1-invitations.md): Создаёт pending invitation в Vault со списком групп, в которые юзер попадёт при accept. Валидация: email свободен (нет User и активного инвайта), все группы принадлежат Vault'у. Регистрация в системе возможна ТОЛЬКО по приглашению — better-auth hook блокирует sign-up без него. Инвайты бессрочные (MVP). - [Инвайт по токену (публичный)](https://docs.v3.finance/api-reference/get-api-v1-invitations-by-token-token.md): Публичный endpoint без авторизации — используется страницей /accept на фронте, чтобы показать "You're invited to as ". Безопасность держится на энтропии token (16 random bytes hex). Для revoked/accepted инвайтов возвращает 410 Gone. - [Принять инвайт (debug)](https://docs.v3.finance/api-reference/post-api-v1-invitations-accept-debug.md): Для отладки/curl-тестов. В реальном flow accept происходит автоматически в better-auth databaseHooks.user.create.after: находится pending инвайт по email, создаются PolicyGroupMembership, инвайт помечается accepted. Этот endpoint вызывает ту же логику для уже существующего User. - [Детали инвайта](https://docs.v3.finance/api-reference/get-api-v1-invitations-id.md): Полные данные инвайта, ВКЛЮЧАЯ token (для копирования magic-link). В реальной системе здесь должна быть авторизация — на MVP пропущена. - [Отозвать приглашение](https://docs.v3.finance/api-reference/post-api-v1-invitations-id-revoke.md): Помечает pending invitation как revoked. Accepted инвайт отозвать нельзя — вместо этого удалите пользователя из групп. - [Группы пользователя](https://docs.v3.finance/api-reference/get-api-v1-users-userid-policy-groups.md): Плоский список групп, в которых состоит пользователь, с membershipId (для DELETE /policy-groups/{id}/members/{membershipId}). Без vaultId возвращает группы из всех Vault'ов. - [Назначить роль пользователю](https://docs.v3.finance/api-reference/patch-api-v1-users-id-role.md): Admin выставляет роль пользователя: admin (полный доступ к конфигу Vault'ов, реестрам, политикам) или user. Так назначается второй и последующие админы; первый создаётся scripts/create-admin.ts. - [Vault пользователя](https://docs.v3.finance/api-reference/get-api-v1-me-vault.md): Возвращает Vault, в группах которого состоит пользователь, со структурой routes (только enabled-варианты). Если членства в нескольких Vault'ах — возвращается первый найденный (MVP: считаем что юзер в одном Vault). Используется landing-страницей юзера. - [Разрешённые сегменты](https://docs.v3.finance/api-reference/get-api-v1-me-allowed-segments.md): Какие значения сегментов derivation path разрешены пользователю для action'а. UNION по всем allow-политикам юзера в Vault: из senderPattern селекторов require-rules извлекаются разрешённые pathId; политика без senderPattern разрешает всё ("*"). Block-политики игнорируются — они сработают на самом submit'е. Используется UI формы создания адреса, чтобы показывать только доступные варианты. - [Зарегистрировать push-токен](https://docs.v3.finance/api-reference/post-api-v1-me-push-tokens.md): Привязывает Expo push token к текущему пользователю (мобилка вызывает после логина и при смене токена). Идемпотентно: повторный тот же токен просто обновляет запись; токен, привязанный к другому юзеру, переезжает на текущего (смена аккаунта на устройстве). - [Снять push-токен](https://docs.v3.finance/api-reference/delete-api-v1-me-push-tokens-token.md): Удаляет токен (логаут устройства / выключение пушей). Удаляет только если токен принадлежит текущему пользователю. - [Мой профиль](https://docs.v3.finance/api-reference/get-api-v1-me-profile.md): Профиль текущего пользователя (из сессии). - [Обновить мой профиль](https://docs.v3.finance/api-reference/patch-api-v1-me-profile.md): Частичное обновление своего профиля: name, username, image (аватар), color, emoji. Все поля опциональны, null — очистить (кроме name). username уникален глобально — занят → 409. ## Help Center - [Help Center](https://docs.v3.finance/help-center.md): No description found - [How do I access my V3 Custody wallet?](https://docs.v3.finance/help-center/faq/how-to-access-wallet.md): Steps to access your V3 Custody wallet. - [Cannot Sign Transaction](https://docs.v3.finance/help-center/troubleshooting/cannot-sign-transaction.md): What to do if you can't sign transactions. - [Adding a New Custody Account](https://docs.v3.finance/help-center/guides/add-new-custody-account.md): How to create a new custody account in V3 Custody. ## Changelog - [Changelog](https://docs.v3.finance/changelog.md): Track version history, recent updates, breaking changes, and new features in V3 Custody.