# Changelog
Source: https://docs.anchorage.com/agentic-banking/changelog
User-visible changes to Anchorage Agentic Banking and these docs.
You can now see a received payment's screening status on the payment itself,
in addition to the payments page. The label is the same one shown on the
payments page: **Screened**, **Under review**, **Blocked on screening**,
**Not screened**, or **Screening status unavailable**.
Start at [llms.txt](https://agentic.anchorage.com/llms.txt) for the live service
catalog, authenticated tools, and public API description. Use this index in
place of the retired enrollment and payment walkthrough.
The **Agents** page has a **Replit** tab. It gives you a one-click **Add to
Replit** link and the display name and server URL to paste into Replit's
**Add MCP server** dialog. After **Test & save**, Replit opens the usual
consent screen where you pick the agent this connection acts as. The public
merchant catalog page has the same tab for its no-sign-in endpoint.
Payments you receive now show their compliance screening status next to the
transaction: **Screened**, **Under review**, **Blocked on screening**, **Not
screened**, or **Screening status unavailable**. Payments you send are
unchanged.
An agent reads a payment's approval status and details only for the payments it
created. A payment another agent created is not visible to it, even when both
agents belong to the same organization. This does not change what people see:
org admins and members keep the same view of payments they had before.
Minting is refused once an agent has ten active API keys. Revoking a key frees
a slot, so you can mint a new one once you're at the limit. Minting is also
rate limited: you can mint many keys in quick succession, and once that
allowance is spent, further mints are refused for a short while. Either
refusal shows a plain-language reason on the agent's page.
An agent can now authenticate with an API key, so a client that runs with no
browser connects without an OAuth consent. An org admin, or the user the agent
acts for, mints a key on the agent's page and the client sends it to the MCP
endpoint as a bearer token. An agent can hold several keys, one per client or
workflow.
The key appears once, at mint. Copy it then; if you lose it, mint another.
Keys never expire, and revoking one from the same page takes effect
immediately.
Linked-card operations still run under an OAuth session, because a card
purchase returns live card credentials and depends on a person approving that
purchase in the browser.
A key stops working with the agent it belongs to. Revoking or pausing the agent
stops its keys immediately, and removing from your organization the member an
agent acts for revokes that agent's keys.
When a card's network can't set up agentic payments for cards from that
card's issuer, the error on the cards settings page now names the network and the
issuer, when the network reports them, instead of a bare status code. If
you see this error, try a different card.
On the crypto rail, where a merchant charges the payment itself rather than
returning the resource, the payment completes when the merchant acknowledges
it. A merchant that answers without acknowledging — no readable
acknowledgement, one naming a different payment, or one reporting failure —
returns an error quoting the merchant's own response, so an agent can read why.
The payment reached the merchant either way, and the merchant may still take
it, so paying again under a new idempotency key risks paying twice. Confirm
on chain, or with Anchorage, before re-attempting — the merchant holds the
credential and is the party that would submit it.
Merchant enablement requests are paused. An org admin can no longer request
merchant enablement, and Anchorage is not deciding open requests for now.
Every decision already made stands: an org that is already merchant-enabled
stays enabled, and the org settings page still shows the most recent request's
status and the reason for a denial.
Merchant compliance screening runs when a merchant is reviewed for activation
and again on periodic rescreens. A merchant that compliance screening flags is
refused at review or deactivated later, and agents can no longer pay it.
A merchant deactivated on 2 or 3 September stays deactivated. Ask Anchorage to
review it again.
The per-payment limit on agent spend is now the smaller of two limits
Anchorage sets independently: a per-payment cap, and a travel-rule block of
\$2,099 that no agent payment may exceed whatever the cap is raised to.
Nothing changes for you today: the cap is \$250, so the limit an agent
meets on the crypto rail and the linked-card rail alike is still \$250. A
payment above it is declined outright, whatever room the agent's budget has
left, and no approval lifts it. What changed is the headroom: raising the
cap now raises the limit as far as \$2,099 without a further change.
The separate \$1,000-per-UTC-day cap per agent is unchanged. See
[Stopping a runaway agent](/agentic-banking/concepts/agents#stopping-a-runaway-agent).
Repeated code attempts for one email address during sign-in are now limited.
If you enter a correct one-time code and it's rejected, wait a moment and
try again.
Merchant compliance screening was strengthened. Merchants are screened when
they are reviewed for activation and again on periodic rescreens; a merchant
that screening flags is declined at review or deactivated later, and agents
can no longer pay it.
`agentic.anchorage.com/robots.txt` and `/llms.txt` return those files. If you
fetched either one before and got the sign-in page with a success status,
fetch it again.
`/llms.txt` is an index for agents, in the [llms.txt](https://llmstxt.org)
format. It points at the unauthenticated merchant catalog, at the
authenticated endpoint that holds the wallet and payment actions, and at the
description of the public API. An agent looking for a service to pay for
should read it first and then search the catalog, since the catalog pages
render results for a query rather than listing every service.
`/robots.txt` opens the landing page, the merchant catalog, `/llms.txt`, the
agent instructions, the OpenClaw skill file, and the public API description to
crawlers. Signed-in pages stay closed to them.
[Discovery](/agentic-banking/concepts/discovery) covers both files and the unauthenticated
catalog endpoint.
Connecting an MCP client before you have picked an organization, on your
first sign-in or when you belong to several, now sends you to the
organization picker and brings you back to the consent screen once you pick
one. You accept an invitation or join an organization open to your email
domain if you need to, choose which agent the client links to, and the
connection completes, where the client used to receive an error. Two cases
still need a restart from the client: taking more than thirty minutes to
pick, or a client authorize request too long for the browser to remember.
Both land you on the dashboard after you pick.
When a payment on one of the newly payable URLs is signed but never makes it
onto the chain, the funds it reserved are released and the payment is closed
automatically, once the network confirms the payment can no longer be
completed. The budget it drew against becomes available again without anyone
having to intervene.
A payment on one of the newly payable URLs comes back carrying the merchant's
own answer to it, whether the merchant accepted the payment or refused it. The
response is marked as shortened only when it was actually too long to return
whole, and the completion message names the rail that handled the payment.
Agents do nothing differently.
Agents can now pay paid URLs whose merchants quote a price in a way the
platform previously could not settle. Agents do nothing differently: how to
pay is read from what the URL asks for at payment time, and a cost preview
prices the same URL the same way. The newly payable quotes are payable on GET
requests only: a price quoted in answer to a write is refused rather than
paid, because paying it would leave the agent unable to tell whether calling
again repeats the change.
Extra request headers on a payment or cost preview — an API key, a content
type — reach the paid URL whether the agent passes them as a JSON object or
as a JSON-encoded string, and a headers value of any other shape is refused
with an error naming what was sent, before anything is fetched or paid.
Previously the object form was silently ignored, so a payment could settle
against the response the URL gives an unauthenticated caller.
A request body must be a string: a body sent as an unencoded JSON document
is refused with an error asking for the string form, before anything is
fetched or paid. Previously that shape was silently sent as an empty body.
Registering an MCP client and revoking a token are now rate-limited: repeated
registration or revocation attempts are refused once they arrive faster than
the limit allows. An agent's first reach of an endpoint URL nobody has
registered yet is rate-limited per agent. Once an endpoint URL is
registered — whether or not a payment on it completes — later calls to that
URL are not limited, and a normal connect — one registration, one consent —
stays well inside the limit.
A registration or revocation request that hits its limit comes back as a
standard HTTP 429 with a `Retry-After` header and the `X-RateLimit-Limit`,
`X-RateLimit-Remaining`, and `X-RateLimit-Reset` headers, so a client can wait
exactly as long as the response asks and then retry. A payment tool call that
hits its limit returns an error naming the limit; retry shortly.
Every request body is also capped at 2 MiB: a request that declares a body
larger than that is refused with a `413` before it reaches the requested
action, unless another protection, such as cross-origin request blocking,
refuses it first. A request sent without a declared size that turns out to
exceed the cap is refused once the cap is hit while reading it. See
[Agents](/agentic-banking/concepts/agents) for the details.
When a payment or cost preview cannot reach the paid URL — the hostname does
not resolve, the connection is refused or unreachable, or the request times
out — the agent now receives an error naming the host and the cause, so it
can report the failing address instead of retrying blindly. These failures
used to return the generic reference-ID error. A URL whose host points at a
private or reserved network address is reported the same way as one that does
not resolve. Failures inside Anchorage Agentic Banking still return the
reference-ID message so support can trace them.
A cost preview for a paid URL now names the payment rail its price applies to,
alongside the amount, asset, chain, and recipient it already reported.
A preview still moves no money, and it quotes the merchant's terms rather than
clearing the payment: an agent that gets a price can still be refused when it
pays, because paying applies budget, screening, and wallet checks a preview has
nothing to run them against. The agent-facing tool text now says so, so an
agent reports a price as a price rather than as an approval.
The Deposit page fetches the details for whichever deposit option you pick, so
picking one is what shows you where to send funds. The page tells you while it
is fetching them.
A payment to a merchant who also banks with Anchorage Agentic Banking now
credits the receiving account from the same on-chain transfer that debits the
payer, so a paid balance reflects the money that arrived and reconciles
against the chain.
Signing in identifies you, and you choose which organization to enter. Your
first sign-in lands on the organization picker, which lists your pending
invitations and every organization open to your email domain. Accept an
invitation or click Join, and you are a member; later sign-ins take you
straight to the organization you belong to.
An organization is open to your email domain when it admits anyone with an
address at that domain. When one matches an address you have verified and you
are not a member, it appears under **Organizations you can join** with a Join
button — on the organization picker when you have no organization yet, and on
**Settings** once you do. You join at the standard member role, so accept the
invitation instead when someone invited you as an admin. An organization you
were removed from stays out of that list; ask an admin there to restore your
access.
A payment record now carries two budget versions: the version read when the
payment started, and the version in effect when the funds were authorized.
When they match, nothing changed mid-payment. When they differ, you can see
which rule applied. Both appear on the payment detail page and in the payment
record the API returns.
This records the budget the payment draws on directly. A budget nested under a
parent is still checked against its parents as well, and their versions are
not recorded.
A Solana payment that settles on chain in the brief moment between the
merchant receiving the signed payment and Anchorage recording that delivery
now completes automatically: the settlement is recognized whichever side
finishes first, and the payment reaches its normal completed state with funds
accounted for exactly once. Payments on Base already behave this way.
In the rare case a crypto payment is interrupted at the moment of signing —
before any payment authorization is recorded — the agent now receives a
structured conflict explaining that reserved funds stay held and that
retrying with the **same** idempotency key re-enters normal payment
processing.
Every org admin now has the Deposit page and its navigation entry, so any
organization can fund its account by deposit. Incoming deposits still go
through the same compliance screening before the funds release to your
available balance.
While an account is locked for review, the Deposit page now withholds its
crypto deposit addresses — generating a new address and viewing the current
one are both refused, and the page explains the lock in place of the
address. The account's deposit history stays visible throughout,
and deposits already on their way to a previously issued address still
arrive and follow the usual screening steps. A frozen account is unchanged:
it still accepts deposits and still shows its deposit addresses.
Creating or editing a budget — including the budget created with a new agent
— now requires the merchant scope to either allow all merchants or name at
least one; an empty allowlist returns a clear validation message. To
deliberately stop a budget's spending, pause it — pause is reversible. An
existing budget with an empty allowlist can still be edited to a valid
merchant scope, paused, or revoked.
A Solana payment authorization is signed against recent network state and can
only land on chain for a short window. When that window has provably closed
and the network shows no settlement, the payment now declines automatically
and its reserved funds release — matching what already happens on Base. A
payment whose settlement did land on chain completes as usual.
When Anchorage consolidates duplicate entries for one merchant in the
merchant catalog, budgets whose allowlist names the duplicate now follow
to the surviving entry automatically. The budget keeps admitting the same
real-world merchant, and its cap and spend-to-date stay untouched. See
[Budgets](/agentic-banking/concepts/budgets).
When a paid URL quotes its price, the quote may also name the resource
being sold. That name must now sit at the same address as the URL actually
reached — the same host and port, so a sibling or CDN subdomain counts as a
different address. A mismatch refuses the payment before anything is
signed, and a cost estimate for the same URL reports the same refusal.
Merchant screening is keyed by the resource's address, so a mismatched
address could otherwise let one merchant present itself as another. Quotes
that omit the resource name keep working unchanged. See the failure-modes
table in [Crypto payments](/agentic-banking/concepts/payments#failure-modes).
A pending invitation to an organization whose setup did not finish now shows
**Setup incomplete** in its row instead of an Accept button — accepting
becomes available the moment Anchorage completes the organization's setup.
Declining stays available throughout. Signing in also now requires an
organization that is ready for you: an invitation to an organization with
incomplete setup admits you once that setup completes, or once another of
your invitations or memberships points somewhere active. (Organizations are
active from the moment they are created — see the entry below — so this
state is rare and always something Anchorage resolves, never a step you wait
out.)
The organization chooser — including the pending-invitations view shown
before you belong to an organization — now names the account you are signed
in to and includes a sign-out button. Signing in with the wrong account
recovers in one step: sign out from the page and sign back in with the right
account.
A new organization is active from the moment Anchorage creates it. Anyone it
invites can accept and sign in straight away, and paying, transferring, and
approving a queued payment all work immediately.
Anchorage's onboarding checks on an organization and its members still run in
full — they complete as the organization is set up. This replaces the separate
activation step described in the 2026-07-27 entry below.
An organization can still be frozen, which stops payments and transfers and
pauses its agents, and approving a queued payment stays blocked until it is
unfrozen.
The merchant directory at `/merchants` now returns results whether or not you
are signed in: a signed-out search shows the same live merchants a signed-in
user sees.
An invited member can now sign in for the first time with the email address
the invitation was sent to, whatever its domain — a personal address, or a
contractor's own company address, for example. Signing in creates their
account and shows them the invitation; accepting it is what adds them to the
organization, with the role the invitation specified. An expired, revoked,
or already-accepted invitation grants nothing.
Sign-in for a domain with an identity provider configured still goes through
that provider. Someone invited from outside that domain signs in with an
email code and accepts the invitation the same way.
Two cases decline an invitation at the moment it is accepted: an organization
that has since restricted membership to its own email domain, and one still
awaiting activation. Both leave the invitation open — the first needs a fresh
invitation from an address the organization now admits, the second only needs
activation to finish.
A new organization now starts in a review state and must be activated by
Anchorage's compliance team before it can be used — signing in, paying,
transferring, and approving a queued payment wait until activation. Existing
organizations are already active and unaffected. Merchant availability is
likewise reviewed by Anchorage's compliance team.
Visiting [agentic.anchorage.com](https://agentic.anchorage.com) without being
signed in now shows a short starting page linking to sign-in, these docs, the
product overview, and a way to reach us. If you are already signed in, you go
directly to your account.
You can now switch to sandbox mode to try deposits and payments on a test
network without moving real funds. Your sandbox balance is kept separate from
your live one, and test-network deposit addresses differ from your live ones —
copy the address shown for the network you are on. Switch back to your live
account at any time.
Approving a payment that is waiting in the approval queue now checks the
organization's status first: if the organization is frozen, the approval is
rejected with a message naming the reason and the payment stays in the queue.
The same check runs when an approved payment is re-issued. Nothing is lost —
once the organization is unfrozen, the approval and re-issue work as before.
On a computer you can now collapse the navigation sidebar to give the page
more room, and open it again from the menu button in the top bar — the
sidebar stays the way you left it as you move between pages. The bar holding
the logo and the light and dark theme controls now sits at the top of every
screen, on computers as well as phones.
The navigation menu on phones opens from the top bar, the Escape key
closes it, and keyboard focus moves into the menu when it opens and
returns to the menu button when it closes. Switching between light and
dark themes is available directly from the top bar on phones. The
sidebar also keeps the current section highlighted while you view its
subpages — for example, a card's detail page keeps Cards highlighted —
so it is always clear where you are.
Paging through long lists — purchase requests, budgets — uses an opaque
marker to fetch the next page. A corrupted or outdated marker now returns a
clear invalid-request error, and restarting the listing from the first page
recovers. Markers issued before this release are invalidated once at rollout,
with the same recovery.
This documentation now lives at docs.anchorage.com/agentic-banking. Old
links under agentic.anchorage.com/docs redirect here automatically, so
bookmarked pages keep working. The docs MCP server moved with it: requests
to the old address are redirected with the method preserved, which most
MCP clients follow transparently — if yours does not, update its
configured address to docs.anchorage.com/mcp. Updating saved links is a
good idea either way.
Finding a merchant now happens in one place: the merchant catalog, browsable
by anyone in the web UI — signed in or anonymous — and searchable by agents
over MCP. An agent's results are limited to what it can actually pay on its
network (mainnet or testnet), and this catalog search is now the only way
an agent discovers where it can pay; the earlier separate list of allowed
merchants has been retired in its favor. Each result now also shows
the merchant a service belongs to, whether that merchant runs the service
itself or resells another provider's, and the payment methods the service
accepts, so an agent can tell up front what it's able to pay and who it's
dealing with. Services from the same merchant are grouped together, and
pulling a single service's detail lists the payment methods its endpoints
accept. Only merchants that have cleared review appear in results.
Agents can now report problems with the merchant catalog as they browse it. When
an agent cannot find a merchant it expected, finds that no merchant offers what
it needs, hits a service that does not work, or gets search results that miss the
mark, it can send that feedback to Anchorage Agentic Banking — noting the search
it tried or the service in question. The reports help us fill gaps in the catalog
and fix listings that have gone stale.
The Deposit page now warns when a Solana deposit address still needs its token
account created. If you see the warning, complete the setup before sending
funds to that Solana address. Existing ready addresses are unchanged.
Agents can now make crypto payments with USDC on Solana, alongside USDC on
Base — Anchorage Agentic Banking automatically settles on Solana when a
merchant prices a request there. You can also fund your account by depositing
USDC on Solana; it credits your account's USD balance on that network
(mainnet or testnet — Base and Solana deposits feed the same balance, not
separate ones per chain) and is screened like any other deposit. Existing
Base payments and deposits are unchanged.
After you attribute a self-hosted deposit sender once, later deposits from the
same sender in your org can reuse those details automatically. The deposit still
runs screening before funds become available, so a fresh review can still block
the funds.
Agents can now find merchants and services to pay by describing what they
need — for example, "web search" or "image generation" — instead of needing
a URL up front. Search returns the matching live merchants, and an agent can
then pull a service's payable endpoints and documentation links to make the
call. Only merchants that have cleared review appear in results.
Linked-card compliance screening was strengthened. As before, a card that does
not pass is refused at link time and stays in your card list, marked with the
reason.
When a deposit reads **Needs attribution**, you can now enter the sender's
name and country directly from your deposit history. Submitting those details
runs the review and releases the funds in the same step if it passes.
When an agent connection does not pass compliance screening, its whole
session now ends and the agent must reconnect to continue. No action
required — a runaway agent is stopped at the connection.
Each deposit now shows where it stands in review: **Needs attribution**,
**Reviewing attribution**, **Cleared**, or **Blocked on screening**. A deposit
becomes available to spend once it reads **Cleared**. The label sits next to
each deposit in your deposit history, so you can tell at a glance whether
funds are ready or still in review.
Paid URLs that return large payloads now come back to your agent whole:
responses up to 10 MB are delivered in full, so data-heavy APIs behind a paid
URL work as expected.
Linked-card support now runs compliance screening when a card is linked and on
each purchase. A card or purchase that does not pass is refused; rejected cards
stay visible in your card list for audit, marked with the reason. No action
required — if a link or purchase is refused, the web UI explains why.
The first public release of **Anchorage Agentic Banking**, alongside the
launch of this docs site.
* **Two payment rails.** Crypto payments to paid URLs on the open
internet, and linked-card purchases via a one-shot credential scoped
per merchant. Each agent can use both rails and picks one per spend.
* **Agent-scoped budgets.** Org admins pre-authorize crypto spend with
a USD spend limit and a merchant allowlist; agents see the limit, not
the account balance.
* **Per-purchase passkey approval for linked cards.** Each card purchase
an agent requests goes through a fresh passkey approval in the
browser.
* **Safety cap that no approval can override.** \$1,000 per UTC day, per
agent, across both rails.
* **Instant revoke** of any agent from the web UI, with no grace window.
* **Sign-in** via work SSO or a one-time email code.
Orgs fund their account by stablecoin deposit on the supported crypto
chains; each deposit credits the account as USD at confirmation. Bank
linking and ACH deposits are on the roadmap.
The docs cover the [agent connection flow](/agentic-banking/guides/connect-an-agent),
the [concepts](/agentic-banking/concepts/agents) behind agents, accounts, budgets,
payments, and linked cards, and per-action
[how-to guides](/agentic-banking/guides/make-a-crypto-payment).
# Accounts
Source: https://docs.anchorage.com/agentic-banking/concepts/accounts
Your org's USD balance per network, and how to fund it.
An **account** is your org's balance on Anchorage Agentic Banking. Your org
has one account per network it runs on (mainnet and/or testnet), each
denominated in **USD** as a single decimal figure. Every member of the org
accesses their org's accounts through their org membership.
## Where to find it
The **dashboard** (the home page in [agentic.anchorage.com](https://agentic.anchorage.com)
after sign-in) shows org admins the current balance for each network. It
also shows the amount held against pending payments and approvals, so the
dashboard displays both the **available** balance and the **held** amount
separately. Plain org members don't see the org balance; their dashboard
view stops at their own budget slice (see [Budgets](/agentic-banking/concepts/budgets)).
## How it gets funded
The **Deposit** page in the web UI is the funding entry point. Anchorage
Agentic Banking generates a deposit address for each crypto chain it
supports.
While an account is locked for review, its deposit addresses are
unavailable — the Deposit page says so in place of the address, and both
generating a new address and viewing the current one wait until the lock
lifts — while the account's deposit history stays visible.
Deposits arrive the same way whoever sends them. When the sender is another
Anchorage Agentic Banking customer — an agent paying for your priced service,
say — that payment credits your account like any other arrival, and the paying
account is debited by the same transfer.
A crypto deposit moves through four steps before it's spendable:
1. **Deposit** — on the Deposit page, pick the chain you're depositing on
to see its address, then send funds there. Some addresses need
one-time setup before they're ready to receive funds; the Deposit page
warns you if yours does. Follow that warning before sending funds.
Testnet and mainnet deposit addresses are different: copy the address
shown for the network you are transacting on — funds sent to the other
network's address land in a separate balance.
2. **Confirm** — the deposit shows as **pending** until the chain confirms
(seconds in practice), then moves to **confirmed**. Anchorage Agentic
Banking converts the incoming crypto to USD as part of that step, so the
balance you see is always one USD figure regardless of which chain the
deposit came in on. The Deposit page shows the rate each accepted token
converts at, so you can check what a deposit will credit before you send
it.
3. **Screen** — a confirmed deposit still needs to clear compliance
screening before the funds release. Each deposit carries one of these
labels:
| Label | Meaning |
| --------------------- | ----------------------------------------------------- |
| Needs attribution | We need the sender's details before the funds release |
| Reviewing attribution | Details received, review in progress |
| Cleared | Review passed, funds available |
| Blocked on screening | Review did not pass |
When a deposit reads **Needs attribution**, the form to provide the
sender's name and country appears directly in your deposit history — no
extra step to open it. Submitting those details runs the review and, if
it passes, releases the funds in the same step. After you attribute a
self-hosted sender once, later deposits from that same sender in your org
can reuse those details automatically; each deposit still runs screening
before the funds become available, so a later review can still leave
funds blocked.
4. **Release** — once a deposit reads **Cleared**, the funds are available
to spend.
Bank linking and ACH deposits are on the roadmap.
## How budgets draw against the account
When an agent spends against a [budget](/agentic-banking/concepts/budgets), the spend
consumes part of the account's USD balance, bounded by the budget's cap.
## What spends from the account
Today, the account funds **crypto payments** — each crypto spend draws
from the USD balance. Linked-card purchases settle through the card's own
issuer rather than through the account, so a linked-card spend leaves the
account balance alone. See [Cards](/agentic-banking/concepts/cards) for the linked-card
flow.
Spending directly from the account at card-accepting merchants is on the
roadmap — it would let an agent use the account balance at any merchant
that takes cards, with no external card linked.
## What the agent sees
The agent sees the **spend limit** configured by the budget it draws on:
its allotted cap and spend-to-date. See [Budgets](/agentic-banking/concepts/budgets) for
the limit model.
# Agents
Source: https://docs.anchorage.com/agentic-banking/concepts/agents
What an agent is in Anchorage Agentic Banking, and how it gets authorized to spend.
An **agent** is a non-human principal that holds credentials to call Anchorage
Agentic Banking's MCP tools on behalf of a user.
Agents are first-class: each has its own identity, audit trail, and scoped
permission to draw against [budgets](/agentic-banking/concepts/budgets).
## Authorization model
An agent acts under exactly one user-org pair at a time. When the agent calls a
tool, Anchorage Agentic Banking resolves three things:
1. **Who is calling** — the agent's credential identifies the agent.
2. **For whom** — the agent is scoped to one user-org membership.
3. **Against what** — the agent has a list of [budgets](/agentic-banking/concepts/budgets) it
may draw on.
The list of allowed budgets is returned inline when the agent introspects its
identity, so an agent gets everything it needs in one call.
An agent authenticates with either an OAuth session or an API key. A client
gets an OAuth session by running the browser consent flow; an org admin or the
agent's user mints an API key on the agent's page in the web UI. Both
credentials authenticate as the same agent acting for the same user, so they
reach the same tools under the same budget scoping. An API key never expires
and authenticates only while its agent is usable.
Minting is refused once an agent has ten active API keys. Revoked keys don't
count against that limit, so revoking one frees a slot for a new one. Minting
is also rate limited per user: you can mint many keys in quick succession, and
once that allowance is spent, further mints are refused for a short while.
[Linked-card](/agentic-banking/concepts/cards) operations run under an OAuth session only,
because a card purchase returns live card credentials and depends on a person
approving that purchase in the browser.
## Crypto and card rails
An agent can use both [payment rails](/agentic-banking/concepts/payments); each individual
spend goes through one of them explicitly, picked by the agent at call time:
| Rail | Authorization | Settlement |
| ----------------------------------------------- | ------------------------------- | -------------------------------------------- |
| Crypto | Budget-scoped, standing consent | On-chain, from the org account's USD balance |
| [Linked cards](/agentic-banking/concepts/cards) | Per-purchase passkey approval | Card-network rails via the issuer |
## Finding merchants to pay
An agent can search the merchants and services it is cleared to pay by plain
description of what it needs, then pull the call detail for the one it picks:
* **Search by need** — the agent describes what it is looking for (for
example, "web search" or "image generation") and gets back the matching
merchant services. This searches only merchants that have cleared review,
limited to the services payable on the agent's own network (mainnet or
testnet), so every result is one the agent can actually pay. Services from
the same merchant are grouped together. Each result carries:
* a name, a short description, and tags
* the merchant it belongs to, and whether that merchant runs the service
itself or resells another provider's
* the payment methods the service accepts
so the agent can tell up front which services it is able to pay and who it
is dealing with.
* **Drill into a service** — given a service from that search, the agent
pulls its payable endpoints — the URLs to pay and the payment methods they
accept — plus pointers to the merchant's API and documentation, so it has
what it needs to make the call.
Search returns a focused, ranked set rather than the whole directory, so an
agent can go from a goal to a payable endpoint in two steps.
## Where agent activity appears
Every payment and approval an agent initiates shows up in the Anchorage
Agentic Banking web UI under the user's history, tagged with the agent's
name — budget-cap overruns on the crypto side and every linked-card
purchase alike.
## Request limits
A few steps around connecting and paying are rate-limited:
* **Registering an MCP client and revoking a token** are rate-limited:
repeated registration or revocation attempts are refused once they arrive
faster than the limit allows. A normal connect — one registration, one
consent — stays well inside the limit. A request that hits this limit
comes back as a standard
HTTP 429 with a `Retry-After` header and the `X-RateLimit-Limit`,
`X-RateLimit-Remaining`, and `X-RateLimit-Reset` headers, so a client can
wait exactly as long as the response asks and then retry.
* **The first time an agent reaches a payment endpoint URL nobody has
registered yet** counts against that agent's limit. Once an endpoint URL
is registered — whether or not a payment on it completes — later calls to
that URL are not limited. A new path under a merchant the agent already
knows still counts as first contact if that exact URL hasn't been
registered before. A payment tool call that hits this limit returns an
error naming the limit; retry shortly.
* **Every request body is capped at 2 MiB.** A request that declares a body
larger than that is refused with a `413` before it reaches the requested
action — unless another protection, such as cross-origin request blocking,
refuses it first. A request sent without a declared size — for example,
chunked transfer encoding — that turns out to exceed the cap is refused
once the cap is hit while reading it.
## Stopping a runaway agent
**\$1,000 per UTC day, per agent, across both rails** — no approval can
override it.
**\$250 per single payment, on both rails** — also beyond any approval.
A crypto payment or a linked-card purchase above that amount is declined
outright, and it stays declined however much room the agent's budget has
left. Approving a payment lets that one payment proceed past the agent's
budget cap, and later payments are still measured against the same cap; the
per-payment limit sits above budgets and holds either way.
The per-payment limit is the smaller of two limits Anchorage sets
independently: a per-payment cap, $250 today, and a travel-rule block of
$2,099 that no agent payment may exceed whatever the cap is raised to.
Today the $250 cap is the smaller of the two, so $250 is the limit an agent
meets. Raising the cap raises the limit only as far as \$2,099.
The two limits are separate controls, and both apply to every payment:
the daily cap bounds what an agent spends across a UTC day, the
per-payment limit bounds any one payment. Anchorage checks each request
against both, and the tighter one for that payment is what declines it.
The daily cap is checked per request against the agent's running total
for the day, so the two controls bind in different places: a $600 payment
is declined by the per-payment limit even on an agent that has spent
nothing that day, and a $200 payment is declined by the daily cap once
that day's total is already at \$900. To spend beyond what the two limits
allow, a person pays it directly.
**Revoke the agent's identity** from the web UI to stop it instantly
yourself, with no grace window: its credentials are permanently invalidated,
every session is revoked, and tool calls fail right away. This is
permanent — the revoked agent can never complete OAuth consent again, so
reconnecting means creating a new agent and consenting for that one.
Anchorage can also pause an agent — for example during an account freeze —
which has the same immediate effect on tool calls and sessions. A paused
agent shows as **Paused** in the web UI; unlike a revoke, pausing doesn't
touch the agent's identity, so once Anchorage lifts the pause the same
agent reconnects with a fresh OAuth consent.
Both controls reach the agent's API keys too. A revoked agent's keys stop
working immediately and permanently. A paused agent's keys stop working at the
pause and are revoked outright, so a client that resumes after Anchorage lifts
the pause needs a freshly minted key.
Removing a member from your organization revokes the API keys of every agent
that acts for that member, and stops those agents.
# Budgets
Source: https://docs.anchorage.com/agentic-banking/concepts/budgets
How agents are pre-authorized to spend on the crypto rail.
A **budget** is a pre-authorized USD spend limit for crypto payments. It is
the spend control on the crypto rail; linked-card purchases use per-purchase
passkey approval instead and are covered separately.
A budget exposes a spend limit to the agent. Every budget references one
[account](/agentic-banking/concepts/accounts) — the funding pool the spend draws against —
but the agent only ever sees the limit, not the account's balance.
## What an org admin configures today
The org settings page exposes one budget per network the org runs on
(typically mainnet and/or testnet). Each budget is **org-wide**: it applies
to every member of the org, and each member gets their own independent USD
cap. The fields the admin sets are:
* **Name** — a label (e.g., "Research travel").
* **Cap (USD)** — the per-member limit.
* **Merchant scope** — either **all merchants** (every merchant Anchorage has
screened and promoted to Active) or a **specific allowlist** picked from
the merchant catalog. A specific allowlist must name at least one
merchant; saving an empty selection is rejected.
When Anchorage consolidates duplicate catalog entries for one merchant,
allowlists naming the duplicate follow to the surviving entry
automatically — the budget keeps admitting the same real-world merchant,
and its cap and spend-to-date stay untouched.
That's the full set of pilot configuration. The underlying model supports
period rollover, parent/child cascades, and per-agent or shared-pool
variants; those will reach the org-settings UI in later releases.
## Period
Pilot budgets are **fixed**: spend accumulates against the cap until the
admin raises it. Daily, weekly, and monthly calendar-period caps are on the
roadmap.
## States and actions
Each budget is in one of three states; the admin can transition between them
from the org settings page:
| State | Meaning | Available actions |
| ------- | ------------------------------------ | ------------------- |
| Active | Budget admits payments under the cap | Edit, Pause, Revoke |
| Paused | Budget rejects all payments | Resume, Revoke |
| Revoked | Budget is permanently disabled | (none) |
## Two gates per payment
Every crypto payment runs through two distinct gates:
1. **Compliance gate** — the merchant must be Active and on the budget's
allowlist. A failure here is a hard reject with no approval path.
2. **Spending gate** — the requested amount, plus existing holds, must fit
inside the cap. See [Approvals](/agentic-banking/concepts/payments#approvals) for what
happens when a payment crosses the cap.
## What the agent sees
Through MCP, the agent reads its own allotted cap, its spend-to-date, and the
merchant allowlist that applies to it. The agent's view is scoped to its own
slice.
## What the org member sees
A member's profile page in the web UI shows their own slice of each org
budget — the cap, the merchants admitted, and a progress bar for spend-to-date.
Each member's view stays scoped to their own slice.
# Linked cards
Source: https://docs.anchorage.com/agentic-banking/concepts/cards
Link your own card; the agent gets a one-shot scoped credential per purchase.
With **linked cards**, the agent itself completes the merchant's checkout.
Anchorage Agentic Banking mints a one-shot credential scoped to that
merchant; the agent uses it to fill in the merchant's own form. The charge
then flows directly through the card network to the issuer.
## Cards belong to the user, not the org
Each linked card is owned by exactly one user. The user links their own card
through a card-verification flow (one-time code plus passkey). An agent
spending on a card always spends on a card the **approving user** linked
themselves — when the approval page asks the user to pick a card, the
picker shows only that user's own cards. Org admins see a read-only roster
of members' linked cards and can revoke on a member's behalf, but they
cannot link, pause, or activate someone else's card.
## Lifecycle of a card purchase
The agent requests a purchase with amount, currency, description, and a
fresh idempotency key. Anchorage Agentic Banking creates a
`PurchaseRequest` in `pending_approval` and returns a link the user opens
to approve.
The user opens the approval link in their browser, picks one of their own
linked cards, and passkey-approves the purchase. The PurchaseRequest
moves to `approved`.
The agent waits for the verdict via a long-poll (\~25 s) using the same
idempotency key. Requests expire 2 hours after creation.
The agent requests credentials, passing the merchant name, URL, country
code, and (for physical goods) the shipping block. Anchorage Agentic
Banking returns card credentials scoped to that merchant — a **one-shot**
retrieval, bound to the merchant at the credential-mint moment.
The agent fills the merchant's checkout form with the credential. The
merchant's payment processor charges the issuer directly through the
card network.
## Approvals
Every linked-card purchase requires a fresh passkey approval — see Approve
and Long-poll above for the mechanics. Every pending approval also lists in
the Anchorage Agentic Banking web UI under **Approvals**, alongside the
direct link from the purchase request itself.
When the user denies a request, the agent mints a new PurchaseRequest with
a new idempotency key to try again — the denied key stays bound to the
denied request.
## Scoped per purchase
Linked-card spend is gated per purchase by passkey approval. Each
PurchaseRequest is its own event, bounded by the amount the user approved.
Card purchases also count toward the same cross-rail daily safety cap as
crypto payments — see [Stopping a runaway agent](/agentic-banking/concepts/agents#stopping-a-runaway-agent).
## Idempotency
`(AgentID, IdempotencyKey)` is the uniqueness shape. The same key from a
different agent on the same owner mints a fresh PurchaseRequest. Use a fresh
key per intent.
## What Anchorage Agentic Banking captures
When the agent retrieves credentials, Anchorage Agentic Banking captures the
merchant context (name, URL, country, optional products, optional shipping
block) into the consumed PurchaseRequest's audit fields. The credential is
bound to that merchant at issuance, so the card network rejects any use at
a different merchant.
## Compliance screening
Linking a card runs compliance screening before the link is registered. A
card that does not pass is refused at link time and shown in your card list
with the reason — the row stays visible for audit, and no purchase ever
reaches that card. Re-trying the same card returns the same refusal.
Each linked-card purchase runs compliance screening before the scoped
credential is minted. A purchase that does not pass is refused with the
reason, and the PurchaseRequest is recorded as rejected.
## Failure modes
| Verdict | What it means | What to do |
| ---------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- |
| Card compliance mismatch | The card itself did not pass compliance screening | Link a different card |
| Card enrollment declined by the network | The card network could not set up the card for agentic payments with its issuer; the error names the network and the issuer when the network reports them | Link a different card |
| Purchase compliance mismatch | The purchase did not pass compliance screening | Mint a new PurchaseRequest with a new idempotency key |
| Credential retrieval — temporary failure | The card network was indeterminate (5xx) | Retry credential retrieval on the same PurchaseRequest — it stays `approved` |
| Credential retrieval — rejected | The card network refused the request (4xx) | Mint a new PurchaseRequest with a new idempotency key |
# Discovery
Source: https://docs.anchorage.com/agentic-banking/concepts/discovery
How an agent finds Anchorage Agentic Banking and the services it can pay, before it holds any credentials.
An agent that arrives at `agentic.anchorage.com` with no account can read what
the product offers and search the service catalog. Both answers come from
files and an endpoint served at the domain root, so an agent author can point
a client at the host and let it read the rest for itself.
## Index at the domain root
`agentic.anchorage.com/llms.txt` describes this host for an agent in the
[llms.txt](https://llmstxt.org) format: a short summary of what Anchorage
Agentic Banking does, then a linked list of the paths an agent uses. It names
the catalog endpoint, the authenticated endpoint that holds the wallet and
payment actions, the public API description, and this documentation site.
An agent reads it before it has a token, which makes it the entry point for a
client that knows only the hostname.
## Searching the catalog without an account
`agentic.anchorage.com/public-mcp` answers catalog queries over MCP without
authentication. An agent describes what it needs in plain words and gets back
the matching merchant services, each with its name, description, tags, owning
merchant, and the payment methods it accepts. Given one of those services, the
agent can pull its endpoint URLs and the merchant's API and documentation
links.
This route runs without a session. Results span every network and endpoints
come back unfiltered, which leaves the agent two things to check. Pick the endpoint on the network you intend to transact
on. And read the payment methods before treating a service as payable, because
a service with no live endpoint still matches a search here and reports none.
Searching is how an agent finds a service. Walking the site does not work,
because the catalog pages render results for a query rather than listing every
service.
The same catalog is available to a connected agent, scoped to the network that
agent is pinned to. That scope is what drops the services this route keeps. See
[finding merchants to pay](/agentic-banking/concepts/agents#finding-merchants-to-pay) for what a
connected agent gets back.
Registering a wallet, checking a budget, and paying for a service need a
connected agent. Those actions live behind the authenticated endpoint, which
answers an unauthenticated request with a `401` and a header naming the
metadata a client needs to start the sign-in flow. See
[connect an agent](/agentic-banking/guides/connect-an-agent) to link a client.
## What crawlers may read
`agentic.anchorage.com/robots.txt` names the public paths a crawler may read
and denies everything else. The file itself is the list, so read it there
rather than relying on a copy. It covers the landing page, the public
paths named in the agent index, the merchant search page with its service and
merchant detail pages, and the styles, webfonts, and favicon the landing page
needs to render. The agent index also names
the authenticated endpoint, which stays denied because a crawler without an
OAuth session gets a 401 there.
Denying the rest is deliberate. Almost every other path requires a session and
answers a signed-out request with a sign-in page, so a crawler let loose on
the host would collect thousands of near-identical sign-in pages.
A crawler reading the policy the way RFC 9309 describes therefore indexes the
pages meant to be public and skips the sign-in redirects. Some older crawlers
read the rules more narrowly and skip the public pages as well. That costs
those crawlers a listing rather than exposing anything, and an agent fetching
`/llms.txt` or the catalog endpoint directly is unaffected either way.
# Crypto payments
Source: https://docs.anchorage.com/agentic-banking/concepts/payments
How Anchorage Agentic Banking settles a paid URL on the crypto rail.
Anchorage Agentic Banking's crypto rail lets an agent pay any URL that
quotes a price. Merchants quote in one of two protocols and the platform
speaks both: [**x402**](https://x402.org), an HTTP-402 challenge/response
that turns a URL into a paywall, and the
[**Machine Payments Protocol**](https://mpp.dev), which quotes in a
`WWW-Authenticate: Payment` header instead.
From the agent's perspective it is a single call either way: supply a URL,
an idempotency key, and the budget to draw on; the platform reads which
protocol the URL speaks and does the rest.
## What Anchorage Agentic Banking does for you
The agent only supplies a URL. Anchorage Agentic Banking owns every merchant-side interaction:
Anchorage Agentic Banking issues the agent's GET or POST to the merchant
URL. On the Machine Payments Protocol only a GET is payable: a price
quoted in answer to a write means the merchant already took the write,
and paying for it would leave the agent unable to tell whether calling
again repeats the change.
The merchant responds with its price: on x402, an HTTP 402 carrying an
`accepts` array of the rails it takes; on the Machine Payments Protocol,
a `WWW-Authenticate: Payment` header naming one.
Where the merchant offers a choice, Anchorage Agentic Banking picks the
cheapest payable entry among the chains the agent is set up to pay on.
Today: USDC on Base (EVM) and USDC on Solana.
Compliance and spending gates run. Failures here return a structured
error to the agent.
Anchorage Agentic Banking signs the payment authorization for the
selected chain — an off-chain EIP-3009 authorization on Base, or an SPL
token transfer on Solana. A Machine Payments Protocol quote is payable on
Solana only, and one naming another chain is refused.
On x402, Anchorage Agentic Banking re-issues the request carrying the
payment credential, and the merchant's facilitator broadcasts to chain.
On the Machine Payments Protocol the credential goes straight to the
merchant's charge endpoint rather than back to the agent, and the
merchant's sponsor broadcasts it and pays the network fee.
On x402 the merchant's response body — the paid resource — lands in the
agent's tool result. On the Machine Payments Protocol what lands there is
the merchant's charge-endpoint response, and Anchorage Agentic Banking
reads it for the merchant's acknowledgement that it took the payment. An
acknowledged charge completes; Anchorage Agentic Banking treats the
acknowledgement as a claim and confirms it against the chain before the
payment is final. A merchant that answers without acknowledging the
charge — no readable acknowledgement, one naming a different charge, or
one reporting failure — returns an error that quotes the merchant's own
response. The payment reached the merchant and the merchant may still
settle it, so paying again risks paying twice. Confirm settlement on
chain, or with Anchorage, before re-attempting: the merchant holds the
credential and is the party that would submit it, so its own answer
cannot settle the question. The protected resource is not re-fetched either, so
treat an acknowledged charge's body as a receipt rather than as the
content.
## Approvals
When a crypto payment exceeds the budget cap (but passes compliance), the
payment is queued as `pending_approval`. The agent gets a structured
response naming the approval; an org admin sees the request in the
Anchorage Agentic Banking web UI under **Approvals** and approves or denies
it.
After an org admin approves, the agent polls for the verdict and then re-issues
the payment with the **same** idempotency key to resume.
An agent polls the verdict for the payments it created. A payment another
agent created stays invisible to it, even inside the same organization.
If the organization is frozen, approving a queued payment is rejected with a
message naming the reason, and the payment stays in the approval queue. The
same check runs when an approved payment is re-issued, so a freeze that lands
after approval still stops the payment. Once the organization is unfrozen,
approving or re-issuing works without any new request.
Pending approvals expire after 24 hours and auto-deny. After that, the
agent mints a new request with a new idempotency key to try again.
Compliance failures (merchant not on allowlist, merchant inactive) are hard
rejects — they stay outside the approval queue.
## Settlement
After signing, the payment stays pending briefly while the merchant's side
broadcasts to chain (its facilitator on x402, its sponsor on the Machine
Payments Protocol). Settlement normally lands in seconds. If
the signed authorization can no longer settle (it expired unused, and the
chain shows no settlement), the payment declines automatically and its
reserved funds normally release back to the account in the same pass — in
the rare case the release needs another step, Anchorage resolves it. Either
way no action is needed from the agent; an agent that still wants the
resource makes a new request with a new idempotency key. A payment whose settlement did land on chain is never
declined this way — it completes as usual.
## Receiving payments
When your account receives a crypto payment — for example, a facilitator or
another Anchorage Agentic Banking customer paying a priced URL you host —
compliance screening runs on the payment before the funds become available.
Each received payment carries one of these labels:
| Label | Meaning |
| ---------------------------- | ----------------------------------------------- |
| Screened | Screening review completed; funds are available |
| Under review | Screening is in progress; funds stay held |
| Blocked on screening | Screening did not pass; funds stay held |
| Not screened | No screening ran for this payment |
| Screening status unavailable | The screening status couldn't be retrieved |
A received payment shows its label on the payments page next to the
transaction, and on the payment's own detail page. Outbound payments you
send carry no screening label.
## Idempotency
`idempotency_key` is **agent-scoped**: two calls from the same agent with the
same key collapse to one transaction; the same key from a different agent is a
separate transaction. Use a fresh key for every distinct intent.
## What the agent sees
The agent sees the URL it asked for and the merchant response body it gets
back. Negotiation detail — which protocol the merchant quoted in, the
accepts array, the signed payload, the facilitator's address, the funding
account's balance — is handled inside Anchorage Agentic Banking and stays
internal.
## Failure modes
| Verdict | What it means | What to do |
| ---------------------------- | --------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ |
| Compliance mismatch | Merchant not on allowlist or inactive | Pick a different merchant |
| Spending mismatch | Over the budget cap | Ask an org admin to approve, then poll for the approval verdict |
| Daily safety cap reached | Hard reject, no approval path | See [Stopping a runaway agent](/agentic-banking/concepts/agents#stopping-a-runaway-agent) |
| Agent deactivated | Hard reject, no approval path | See [Stopping a runaway agent](/agentic-banking/concepts/agents#stopping-a-runaway-agent) |
| Account locked or frozen | Hard reject, no approval path | Contact Anchorage support — resolution requires staff action |
| Insufficient account balance | Hard reject, no approval path | Fund the account, then retry |
| Resource mismatch | The merchant's quote names a resource at a different address (host or port) than the URL actually reached | Hard reject, no approval path. The merchant endpoint is misconfigured; pick a different merchant |
| Schema mismatch | Request body doesn't match the merchant's published schema | Fix the request body and retry with a **new** idempotency key |
| Upstream 5xx | Merchant indeterminate | Retry with the **same** idempotency key — repeat calls collapse to one settlement |
| Interrupted while signing | The payment stopped before an authorization was recorded; reserved funds stay held | Retry with the **same** idempotency key — contact Anchorage support if retries keep failing |
# Buy with a linked card
Source: https://docs.anchorage.com/agentic-banking/guides/buy-with-a-linked-card
What the agent supplies on a card purchase. For mechanics, see Linked cards.
A card purchase takes three steps and one human passkey approval. For the
lifecycle, approval flow, ownership model, and per-purchase invariants
(one-shot credentials, merchant binding, terminal denials), see
[Linked cards](/agentic-banking/concepts/cards). This page lists what the agent supplies.
## Purchase request
* Amount and currency.
* A short merchant-facing description.
* An idempotency key, unique per intent.
* Optionally, a hint for which card the approval page should default to.
Anchorage Agentic Banking returns a `purchase_request_id`, a
`pending_approval` status, and an `approval_url` for the user to open.
## Polling and expiry
The agent long-polls for the verdict (\~25 s per call) using the same
idempotency key. PurchaseRequests expire 2 hours after creation; until then
the agent can keep polling.
## Credential retrieval
After the user approves, the agent requests credentials, providing:
* Merchant name and URL.
* Merchant country code.
* For physical goods, the shipping block: `shipping_line1`,
`shipping_line2`, `shipping_city`, `shipping_region`,
`shipping_postal_code`, `shipping_country`, and an optional `products`
JSON.
Anchorage Agentic Banking returns a card credential — number, expiry,
CVC. The agent fills the merchant's checkout form with the returned
credential.
# Check your budget
Source: https://docs.anchorage.com/agentic-banking/guides/check-your-budget
What the agent can see, and what the user sees in the UI.
## From the agent
The agent gets every budget it may draw on inline on its first turn, by
introspecting its own identity — see [Agents](/agentic-banking/concepts/agents) for what
that introspection returns. The agent can also fetch, on demand:
* Every budget it is authorized for on its network.
* The primary budget's limit, spend-to-date, and period bounds (or a
"no spend limit configured" placeholder).
The agent sees a spend limit, not a wallet balance — see
[Budgets](/agentic-banking/concepts/budgets) for how the cap is enforced. A \$1,000/day/agent
safety cap also applies on top of any budget's own limit; see
[Stopping a runaway agent](/agentic-banking/concepts/agents#stopping-a-runaway-agent).
## From the user
See [What the org member sees](/agentic-banking/concepts/budgets#what-the-org-member-sees)
for where a member's own budget slice appears in the web UI.
# Connect an agent
Source: https://docs.anchorage.com/agentic-banking/guides/connect-an-agent
How an MCP client links to one of your agents.
Anchorage Agentic Banking exposes its tools over MCP. Any MCP-capable client
can connect. For programmatic discovery, see [Discovery](/agentic-banking/concepts/discovery).
## Prerequisites
* A signed-in Anchorage Agentic Banking account. Sign in with your work SSO,
or with a one-time code sent to your email. Repeated code attempts for one
email address are limited; if a correct code is rejected, wait a moment
and try again.
* At least one agent created on the **Agents** page in the web UI, with a
budget assigned by your org admin.
## How linking works
When an MCP client connects to Anchorage Agentic Banking, it triggers an
OAuth consent flow in your browser. During that flow, you pick which of
your agents this MCP session is linking to. The chosen agent's identity is
what the client will act under — every tool call from that session is
attributed to that agent, and every spend draws on that agent's budget.
If you have not picked an organization yet — on your first sign-in, or when
you belong to several — the flow sends you to the organization picker first,
where you pick one, accept an invitation, or join an organization open to
your email domain. Picking one returns you to the consent screen, so you
finish linking without restarting from the client. Two cases do need a
restart from the client: taking more than thirty minutes to pick, or a
client authorize request too long for the browser to remember, both of
which land you on the dashboard after you pick.
Registering a client and revoking a token carry request limits — see
[Request limits](/agentic-banking/concepts/agents#request-limits).
## Per-client setup
Per-client configuration snippets, the MCP endpoint URL, and the OAuth
consent itself all live on the **Agents** page at
[agentic.anchorage.com](https://agentic.anchorage.com). Tested clients today:
**Claude Desktop**, **Claude Code**, **Hermes**, **ChatGPT**, **OpenClaw**, **Replit**.
Any other MCP-capable client should work via the standard MCP OAuth flow.
## Headless and server-side clients
A client that runs with no browser authenticates with an API key instead of an
OAuth session. Mint the key on the agent's page at
[agentic.anchorage.com](https://agentic.anchorage.com), copy it while the page
shows it, and send it to the MCP endpoint as a bearer token in the client's
`Authorization` header. Revoke it from the same page. For what a key
authenticates as and which operations still need the OAuth session, see
[Agents](/agentic-banking/concepts/agents#authorization-model).
## First call
The agent's first turn should introspect its own identity. The response
includes the agent's name, status, linked account, network scope, and its
budgets — enough to start paying without a second round trip.
# Make a crypto payment
Source: https://docs.anchorage.com/agentic-banking/guides/make-a-crypto-payment
What the agent supplies on a paid URL. For mechanics, see Crypto payments.
The crypto rail is a single action. The agent supplies a URL, an
idempotency key, and the budget to draw on; Anchorage Agentic Banking does
the rest. For the full under-the-hood flow, approvals, and failure modes,
see [Crypto payments](/agentic-banking/concepts/payments).
## What the agent provides
* The URL to fetch.
* An idempotency key, unique per intent.
* The budget to draw on (`budget_id`).
* Optional: HTTP method, headers, body. Defaults to `GET` with no body.
## Estimating cost first
If the agent wants to know what a URL will cost before drawing on the
budget, it can pre-flight the URL to get the price back — without
committing any spend.
## Retry cheat sheet
The full table lives in
[Crypto payments → Failure modes](/agentic-banking/concepts/payments#failure-modes). At a
glance:
* **Over the budget cap** → poll for the approval verdict, then re-issue
with the **same** idempotency key.
* **Compliance failure** (merchant inactive / not on allowlist) → switch
merchants.
* **Schema mismatch** → fix the request body, retry with a **new**
idempotency key.
* **Upstream 5xx** → retry with the **same** idempotency key — repeat calls
collapse to one settlement.
* **Daily safety cap reached** → hard reject, no approval path — see
[Crypto payments → Failure modes](/agentic-banking/concepts/payments#failure-modes).
# Quickstart
Source: https://docs.anchorage.com/agentic-banking/quickstart
From zero to first agent payment.
Go to [agentic.anchorage.com](https://agentic.anchorage.com), choose
**Sign in**, and use your org's SSO or the account your admin set up for
you. Your first sign-in lands you on the organization picker, which lists
every organization you can enter: accept a pending invitation, or join an
organization that is open to your email domain. Once you belong to one,
signing in takes you straight there.
An organization is open to your email domain when it admits anyone with an
address at that domain. If one matches an address you have verified and
you are not a member, it appears under **Organizations you can join**, with
a Join button. You join at the standard member role, so accept an
invitation instead when someone invited you as an admin. Look for it on the
organization picker when you have no organization yet, and on **Settings**
once you do — an organization that opens up after your first sign-in shows
up there without your having to sign in again.
An organization is ready to use from
the moment Anchorage creates it, so there is no activation step between
your invitation and your first sign-in. If an organization's setup did not
finish, that invitation admits you once Anchorage completes the setup, or
sooner if another of your invitations or memberships already points
somewhere active; until then it waits on your pending invitations marked
**Setup incomplete**.
Point any MCP-capable agent at Anchorage Agentic Banking. The MCP endpoint
and OAuth consent are linked from the **Agents** page in the web UI.
See [Connect an agent](/agentic-banking/guides/connect-an-agent) for tested clients and
per-client setup.
Once connected, your agent introspects its own identity on its first turn:
name, linked account, and the budgets it can spend against —
everything it needs to start paying.
Ask the agent to fetch a paid URL. The agent pays the URL using its
standing budget. Anchorage Agentic Banking checks the budget and the
merchant allowlist, settles the payment, and returns the merchant's
response to the agent — which returns it to you.
For card purchases, the agent requests a purchase and you passkey-approve
the spend on a browser approval page.
## Next steps
How agents are pre-authorized to spend, and what the spend limit means.
Per-client setup walkthroughs.
The mechanics behind the crypto rail.
Per-purchase passkey approval and one-shot credentials.
How an agent is authorized, and how to revoke one instantly.
# Verifying addresses
Source: https://docs.anchorage.com/knowledge-base/api-reference/address-verification
Verify deposit address authenticity and integrity using Anchorage Digital's V1 and V2 signature schemes.
The addresses REST API endpoints return signatures of the address strings and other metadata that prove the address was generated by Anchorage Digital for your organization.
Verify the address signature and all accompanying metadata before using any address. This confirms authenticity and integrity.
## Signature schemes
The API supports two address verification schemes. Check the `signatureVersion` field to determine which applies.
| Scheme | How it works |
| ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **V1** | Verify signature against a fixed Ed25519 public key unique to your organization, distributed out-of-band by Anchorage Digital. Must be kept tamper-proof. |
| **V2** | Verify signature against the public key of the leaf certificate in an X.509 certificate chain returned with the response, then verify the chain against the Anchorage Digital Address Signing Root CA (hard-coded by the client). |
***
## V1 address signature verification
### Steps
1. **Verify the signature:**
* Decode `addressSignaturePayload` from hex to bytes.
* Decode `signature` from hex to bytes.
* Using your organization's fixed public key, verify that `signatureBytes` is a valid Ed25519 signature of `addressSignaturePayloadBytes`.
2. **Verify the signed address matches the address to be used:**
* Decode `addressSignaturePayload` from hex to bytes.
* Parse the bytes as JSON.
* Verify the address matches the `TextAddress` property in the JSON.
Validating the signature alone is insufficient. You must also confirm that `TextAddress` in the decoded payload matches the address you intend to use.
### V1 signed payload fields
| Field | Description |
| ------------- | ---------------------------------------- |
| `TextAddress` | The text format of the on-chain address. |
```json theme={null}
{
"TextAddress": "2N19AcihQ1a4MxQW658UFHTioUNnMkiHPkw"
}
```
### Sample V1 validation code
```go theme={null}
package main
import (
"crypto/ed25519"
"encoding/hex"
"encoding/json"
"fmt"
)
// V1SignedPayload represents the JSON structure in the addressSignaturePayload for V1 signatures
type V1SignedPayload struct {
TextAddress string `json:"TextAddress"`
}
// verifyV1AddressSignature verifies a V1 address signature.
//
// Parameters:
// - address: The address string from the API response
// - addressSignaturePayload: Hex-encoded bytes that were signed
// - signature: Hex-encoded Ed25519 signature
// - orgPublicKeyHex: Hex-encoded Ed25519 public key for your organization (obtained out-of-band)
//
// Returns an error if verification fails.
func verifyV1AddressSignature(address, addressSignaturePayload, signature, orgPublicKeyHex string) error {
// Step 1: Check the validity of the signature
// Decode the addressSignaturePayload from hex to bytes
payloadBytes, err := hex.DecodeString(addressSignaturePayload)
if err != nil {
return fmt.Errorf("failed to decode addressSignaturePayload: %w", err)
}
// Decode the signature from hex to bytes
signatureBytes, err := hex.DecodeString(signature)
if err != nil {
return fmt.Errorf("failed to decode signature: %w", err)
}
// Decode the organization public key from hex
publicKeyBytes, err := hex.DecodeString(orgPublicKeyHex)
if err != nil {
return fmt.Errorf("failed to decode organization public key: %w", err)
}
if len(publicKeyBytes) != ed25519.PublicKeySize {
return fmt.Errorf("invalid public key size: got %d bytes, expected %d", len(publicKeyBytes), ed25519.PublicKeySize)
}
publicKey := ed25519.PublicKey(publicKeyBytes)
// Verify the Ed25519 signature
if !ed25519.Verify(publicKey, payloadBytes, signatureBytes) {
return fmt.Errorf("signature verification failed")
}
// Step 2: Verify the signed address matches the address to be used
// Parse the payload bytes as JSON
var signedPayload V1SignedPayload
if err := json.Unmarshal(payloadBytes, &signedPayload); err != nil {
return fmt.Errorf("failed to parse signed payload: %w", err)
}
// Verify the TextAddress matches
if signedPayload.TextAddress != address {
return fmt.Errorf("signed TextAddress does not match: signed=%q, expected=%q", signedPayload.TextAddress, address)
}
return nil
}
func main() {
// Sample API response data
address := "2N19AcihQ1a4MxQW658UFHTioUNnMkiHPkw"
addressSignaturePayload := "7b225465787441646472657373223a22324e313941636968513161344d78515736353855464854696f554e6e4d6b6948506b77227d"
signature := "b18f6848dc0fef01a069e7ac26046383bf5cd130203994dc2d72b5a9097351b1e8b67115b63124fbc8c16673566416a635913c670b676089339c62a7824baa03"
// Organization public key - obtained out-of-band from Anchorage Digital beforehand
// Unique per Organization, fixed for the lifetime of that Organization
// Must be kept tamper-proof
orgPublicKeyHex := "8a88e3dd7409f195fd52db2d3cba5d72ca6709bf1d94121bf3748801b40f6f5c"
// Verify the signature
if err := verifyV1AddressSignature(address, addressSignaturePayload, signature, orgPublicKeyHex); err != nil {
fmt.Printf("✗ V1 Address signature verification failed: %v\n", err)
return
}
fmt.Println("✓ V1 Address signature verified successfully!")
fmt.Printf(" Address: %s\n", address)
fmt.Println("\nYou may now safely use this address for deposits.")
}
```
***
## V2 address signature verification
Addresses with `signatureVersion: V2` include a `certChain` field containing an X.509 certificate chain in PEM format.
### Steps
1. **Verify the certificate chain:**
* Parse `certChain` as PEM-encoded X.509 certificates.
* Verify the chain from the leaf to the trusted Anchorage Digital Root CA.
* Verify all certificates are temporally valid (both `notAfter` and `notBefore`).
* Verify the leaf certificate's Subject Alternative Names include `address-provider.anchorage.internal`.
* Verify the leaf certificate's `KeyUsage` includes both `digitalSignature` and `nonRepudiation` (also known as `contentCommitment`).
* Extract the public key from the leaf certificate. Currently only Ed25519 keys are supported, but this may change.
The leaf certificate is at index 0, followed by zero or more intermediates. The root cert is excluded from the response. The number of certificates in the chain may change. Follow standard X.509 verification procedures — not all libraries perform all checks by default.
2. **Verify the signature:**
* Decode `addressSignaturePayload` from hex to bytes.
* Decode `signature` from hex to bytes.
* Using the leaf certificate's public key, verify `signatureBytes` is a valid signature of the payload bytes.
3. **Verify the signed details:**
* Parse `addressSignaturePayload` bytes as JSON.
* Verify `SignatureExpiresAt` ≥ current UTC Unix timestamp.
* Verify `TextAddress` matches the address to be used.
* Verify `VaultId` matches your expected Vault ID.
* Verify `NetworkId` matches the expected network for this address.
`NetworkName` is included for human readability and does not need to be verified. Do not use a "strict" JSON parser that rejects extra properties — future versions may add fields.
Anchorage Digital periodically refreshes V2 signatures and the Address Signing Root CA before expiration. The deposit address itself will not change — only the signature, certificate chain, and Root CA are updated.
### V2 signed payload fields
| Field | Description |
| -------------------- | ------------------------------------------------------------- |
| `TextAddress` | The text format of the on-chain address. |
| `VaultId` | Identifies the vault this address belongs to. |
| `NetworkId` | Identifies the network this address can receive deposits on. |
| `NetworkName` | Human-readable version of `NetworkId`. |
| `SignatureExpiresAt` | Unix timestamp after which the signature must not be trusted. |
```json theme={null}
{
"VaultId": "dae6089e7c0836705f0562af0f1e4e1f",
"TextAddress": "bcrt1q709skemgf5skpsnysvgme2s3ztehkutl390yl0wp29lnmum5uw7qg0qrwm",
"NetworkName": "Bitcoin Regnet",
"NetworkId": "BTC_R",
"SignatureExpiresAt": 1769450713
}
```
### Anchorage Digital Address Signing Root CAs
Hard-code the appropriate Root CA for the environment you are targeting. This value must be tamper-proof.
```
-----BEGIN CERTIFICATE-----
MIIBXTCCAQ+gAwIBAgIUQZI+MSvYTXQHra+3OAKnwAMzotUwBQYDK2VwMCAxHjAc
BgNVBAMMFWNhLmFuY2hvcmFnZS5pbnRlcm5hbDAeFw0yNjAxMjYwMDAwMDBaFw0y
NzAxMjYwMDAwMDBaMCAxHjAcBgNVBAMMFWNhLmFuY2hvcmFnZS5pbnRlcm5hbDAq
MAUGAytlcAMhADTh1nctgIHtAKNW8ww/bY606pJ3OP2dyZYcQrU2kG5jo1swWTAP
BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwICBDAUBgorBgEEAYaNHwEBBAYW
BHJvb3QwIAYDVR0RBBkwF4IVY2EuYW5jaG9yYWdlLmludGVybmFsMAUGAytlcANB
ANkkdudEjH9RTKbRAxrRXyMSS/TgmdSrAVYOZzoRDJlyc+5oD+a0pmmwWVe86xZi
37YbN1GzVlXcJAPpV6ceEQU=
-----END CERTIFICATE-----
```
```
-----BEGIN CERTIFICATE-----
MIIBXDCCAQ6gAwIBAgITOfTQ4rYUsghgvdl8YCJSC67uGDAFBgMrZXAwIDEeMBwG
A1UEAwwVY2EuYW5jaG9yYWdlLmludGVybmFsMB4XDTI2MDEyNDAwMDAwMFoXDTI3
MDEyNDAwMDAwMFowIDEeMBwGA1UEAwwVY2EuYW5jaG9yYWdlLmludGVybmFsMCow
BQYDK2VwAyEAPlBo2/+kPPL0WRpT+B/yHsU25AN/M6HP2bzC61yHb4ajWzBZMA8G
A1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgIEMBQGCisGAQQBho0fAQEEBhYE
cm9vdDAgBgNVHREEGTAXghVjYS5hbmNob3JhZ2UuaW50ZXJuYWwwBQYDK2VwA0EA
YsJxVI9n42liCF9f+Ou7uuC1QGFwaHwFsfOm0WFofSlE1trWqzj4ruzjPYSRJc8H
t2A7XCAfXkG0mzKpL/wQDg==
-----END CERTIFICATE-----
```
### Sample V2 validation code
```go theme={null}
package main
import (
"crypto/ed25519"
"crypto/x509"
"encoding/hex"
"encoding/json"
"encoding/pem"
"fmt"
"time"
)
// V2SignedPayload represents the JSON structure in the addressSignaturePayload for V2 signatures
type V2SignedPayload struct {
TextAddress string `json:"TextAddress"`
VaultId string `json:"VaultId"`
NetworkId string `json:"NetworkId"`
NetworkName string `json:"NetworkName"`
SignatureExpiresAt int64 `json:"SignatureExpiresAt"` // Unix timestamp
}
// verifyV2AddressSignature verifies a V2 address signature.
//
// Parameters:
// - now: The "current" time. Note that conforming implementations must use
// a trusted source for the current time.
// - address: The address string from the API response
// - addressSignaturePayload: Hex-encoded bytes that were signed
// - signature: Hex-encoded signature
// - certChainPEM: PEM-encoded certificate chain (leaf first, then intermediates)
// - rootCAPEM: PEM-encoded Root CA certificate (hard-coded by client)
// - expectedVaultId: Your Vault ID to verify against the signed VaultId
// - expectedNetworkId: Expected network ID for this address (e.g., "BTC", "ETH")
//
// Returns an error if verification fails.
func verifyV2AddressSignature(
now time.Time,
address, addressSignaturePayload, signature, certChainPEM, rootCAPEM, expectedVaultId, expectedNetworkId string,
) error {
// Step 1: Verify the certificate chain
// Parse the certificate chain from PEM
certs, err := parsePEMCertificates([]byte(certChainPEM))
if err != nil {
return fmt.Errorf("failed to parse certificate chain: %w", err)
}
if len(certs) == 0 {
return fmt.Errorf("certificate chain is empty")
}
leafCert := certs[0]
var intermediateCerts []*x509.Certificate
if len(certs) > 1 {
intermediateCerts = certs[1:]
}
// Parse the Root CA
rootCACerts, err := parsePEMCertificates([]byte(rootCAPEM))
if err != nil {
return fmt.Errorf("failed to parse Root CA: %w", err)
}
if len(rootCACerts) != 1 {
return fmt.Errorf("expected exactly one Root CA certificate, got %d", len(rootCACerts))
}
rootCA := rootCACerts[0]
// Verify the leaf certificate's KeyUsage includes both
// digitalSignature and nonRepudiation (AKA contentCommitment)
if leafCert.KeyUsage&x509.KeyUsageDigitalSignature == 0 {
return fmt.Errorf("leaf certificate KeyUsage missing DigitalSignature")
}
if leafCert.KeyUsage&x509.KeyUsageContentCommitment == 0 {
return fmt.Errorf("leaf certificate KeyUsage missing NonRepudiation (ContentCommitment)")
}
// Verify the certificate chain from leaf to Root CA
roots := x509.NewCertPool()
roots.AddCert(rootCA)
intermediates := x509.NewCertPool()
for _, cert := range intermediateCerts {
intermediates.AddCert(cert)
}
// NOTE: Not all x509 libraries are created equal and are not
// guaranteed to verify exactly the same things!
//
// Always review the library you plan to use and ensure it covers the
// checks described in the User Guide!
//
// For example, the Go implementation checks all Certificates for
// temporal validity (notBefore and notAfter against CurrentTime), for
// valid signatures up the chain, and checks that the Subject
// Alternative Names include the values in DNSNames below.
//
// However it does not check the KeyUsage bits, hence the additional
// checks above.
opts := x509.VerifyOptions{
DNSNames: []string{"address-provider.anchorage.internal"},
Roots: roots,
Intermediates: intermediates,
CurrentTime: now,
// NOTE: This allows for any Extended Key Usage, but does not
// check the Key Usage bits, hence the additional checks above.
KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageAny},
}
if _, err := leafCert.Verify(opts); err != nil {
return fmt.Errorf("certificate chain verification failed: %w", err)
}
// Extract the public key from the leaf certificate
leafPublicKey, ok := leafCert.PublicKey.(ed25519.PublicKey)
if !ok {
return fmt.Errorf("leaf certificate does not use Ed25519 (got type %T)", leafCert.PublicKey)
}
// Step 2: Verify the signature
// Decode the addressSignaturePayload from hex to bytes
payloadBytes, err := hex.DecodeString(addressSignaturePayload)
if err != nil {
return fmt.Errorf("failed to decode addressSignaturePayload: %w", err)
}
// Decode the signature from hex to bytes
signatureBytes, err := hex.DecodeString(signature)
if err != nil {
return fmt.Errorf("failed to decode signature: %w", err)
}
// Verify the signature using the leaf certificate's public key
if !ed25519.Verify(leafPublicKey, payloadBytes, signatureBytes) {
return fmt.Errorf("signature verification failed")
}
// Step 3: Verify the signed details
// Parse the payload bytes as JSON
var signedPayload V2SignedPayload
if err := json.Unmarshal(payloadBytes, &signedPayload); err != nil {
return fmt.Errorf("failed to parse signed payload: %w", err)
}
// Verify SignatureExpiresAt is not in the past
if now.Unix() > signedPayload.SignatureExpiresAt {
expiryTime := time.Unix(signedPayload.SignatureExpiresAt, 0)
return fmt.Errorf("signature has expired at %s", expiryTime)
}
// Verify TextAddress matches
if signedPayload.TextAddress != address {
return fmt.Errorf("signed TextAddress does not match: signed=%q, expected=%q",
signedPayload.TextAddress, address)
}
// Verify VaultId matches
if signedPayload.VaultId != expectedVaultId {
return fmt.Errorf("signed VaultId does not match: signed=%q, expected=%q",
signedPayload.VaultId, expectedVaultId)
}
// Verify NetworkId matches
if signedPayload.NetworkId != expectedNetworkId {
return fmt.Errorf("signed NetworkId does not match: signed=%q, expected=%q",
signedPayload.NetworkId, expectedNetworkId)
}
return nil
}
// parsePEMCertificates parses PEM-encoded certificates and returns them as a slice
func parsePEMCertificates(pemData []byte) ([]*x509.Certificate, error) {
var certs []*x509.Certificate
for {
block, rest := pem.Decode(pemData)
if block == nil {
break
}
if block.Type != "CERTIFICATE" {
pemData = rest
continue
}
cert, err := x509.ParseCertificate(block.Bytes)
if err != nil {
return nil, fmt.Errorf("failed to parse certificate: %w", err)
}
certs = append(certs, cert)
pemData = rest
}
return certs, nil
}
func main() {
// Sample API response data
address := "bcrt1q709skemgf5skpsnysvgme2s3ztehkutl390yl0wp29lnmum5uw7qg0qrwm"
addressSignaturePayload := "7b225661756c744964223a226461653630383965376330383336373035663035363261663066316534653166222c225465787441646472657373223a22626372743171373039736b656d676635736b70736e797376676d653273337a7465686b75746c333930796c30777032396c6e6d756d357577377167307172776d222c224e6574776f726b4e616d65223a22426974636f696e205265676e6574222c224e6574776f726b4964223a224254435f52222c225369676e6174757265457870697265734174223a313736393435303731337d"
signature := "951eb2fb560e660aa9c3d1ccd120d3ad1a19d90d8747347057e48bf174330eb386089e3232d822fd66b8183cce8059c91183afde299b920a0e0c05c5b167360e"
certChainPEM := `-----BEGIN CERTIFICATE-----
MIIBYTCCAROgAwIBAgIUMLKt+K9eFku+P7BbefE1xAHg0hcwBQYDK2VwMAAwHhcN
MjYwMTI2MTcwNDEzWhcNMjcwMTI2MTcwNTEzWjAuMSwwKgYDVQQDEyNhZGRyZXNz
LXByb3ZpZGVyLmFuY2hvcmFnZS5pbnRlcm5hbDAqMAUGAytlcAMhAPsgM70aWFYs
ZaLHawtYJpl42BkiTLyCq96+OXe4FxrVo3EwbzAOBgNVHQ8BAf8EBAMCBsAwDAYD
VR0TAQH/BAIwADAfBgNVHSMEGDAWgBS0usSFeB2gjC+wcowtxN3MeKSH7zAuBgNV
HREEJzAlgiNhZGRyZXNzLXByb3ZpZGVyLmFuY2hvcmFnZS5pbnRlcm5hbDAFBgMr
ZXADQQCXmvIkuPnUgCHxWmFmzvgWdv9lUlt84oZCel+OeJW9n8PR88tGxAcD1E3+
KDBXVpO0GcRA0W9+xqqICAo2ROEJ
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIBKDCB26ADAgECAhRGsD05KldIse+uIEa976AijTqlxjAFBgMrZXAwADAeFw0y
NjAxMjYxNzA0MTNaFw0yNzAxMjYxNzA1MTNaMAAwKjAFBgMrZXADIQCNpyY5Sr21
FHNvvLkBKG8AEMKdhqtajmV5d2QaZlmtAqNnMGUwDgYDVR0PAQH/BAQDAgIEMBIG
A1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFLS6xIV4HaCML7ByjC3E3cx4pIfv
MCAga1UdEQEB/wQWMBSCEmFuY2hvcmFnZS5pbnRlcm5hbDAFBgMrZXADQQCIgw6k
LMIwhd3ACjG03cJ5z/ZZp8aXXycFq2ZC9TLhieJ3rncyMH6ZdyJ3Ai1eVaHs4vn
DCv54Vdh83vvSky4K
-----END CERTIFICATE-----
`
// NOTE: This is a FAKE Root CA used just for this example.
// NOTE: Conforming client implementations should hard-code the real
// Anchorage Digital Address Signing Root CA for the environment they
// are making requests to.
rootCAPEM := `-----BEGIN CERTIFICATE-----
MIIBGzCBzqADAgECAhQ2qQwArneTuF0dbNDs8i/ExuyW2DAFBgMrZXAwADAeFw0y
NjAxMjYxNzA0MTNaFw0yNzAxMjYxNzA1MTNaMAAwKjAFBgMrZXADIQB+gEnytXKn
uAMonIWGWnB0qyTqa0aw3l9u5VRbu86UgaNaMFgwDgYDVR0PAQH/BAQDAgIEMA8G
A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFOj64tL1teJHkojsiblnnK34Tw+EMBYGN
A1UdEQEB/wQMMAqCCGludGVybmFsMAUGAytlcANBAAg2IcVEXmWKSivhUNSatNfM
mASxi83QscIuyP/sIW2sRIuCqQJoo9lN6TaxzyV62cQMzthFOCZcgRE+k0JV7Ao=
-----END CERTIFICATE-----
`
// Your Vault ID - obtained from your application context
expectedVaultId := "dae6089e7c0836705f0562af0f1e4e1f"
// Expected network ID for this address
expectedNetworkId := "BTC_R"
// Implementations should use the actual current time
// now := time.Now()
now := time.Unix(1769450600, 0) // Fake time so that this example passes.
// Verify the signature
if err := verifyV2AddressSignature(
now,
address,
addressSignaturePayload,
signature,
certChainPEM,
rootCAPEM,
expectedVaultId,
expectedNetworkId,
); err != nil {
fmt.Printf("✗ V2 Address signature verification failed: %v\n", err)
return
}
fmt.Println("✓ V2 Address signature verified successfully!")
fmt.Printf(" Address: %s\n", address)
fmt.Printf(" Vault ID: %s\n", expectedVaultId)
fmt.Printf(" Network: %s\n", expectedNetworkId)
fmt.Println("\nYou may now safely use this address for deposits.")
}
```
# Authentication
Source: https://docs.anchorage.com/knowledge-base/api-reference/authentication
Authenticate Anchorage Digital API requests with API keys and signatures.
All API requests require the `Api-Access-Key` header.
```http theme={null}
Api-Access-Key: YOUR_API_KEY
```
Some endpoints also require:
```http theme={null}
Api-Timestamp: 1577880000
Api-Signature: 4bf42054bf7db1f8...
```
For how permission groups, keys, and signatures work together, see [API setup](/knowledge-base/platform/developers/setting-up) and [Request signing](/knowledge-base/platform/developers/request-signing).
## How authentication works
API authentication has three layers. Every request needs all the layers that apply to the endpoint you're calling.
A permission group defines which vaults a key can access and what operations it can perform.
An access key identifies the caller and is required on every request.
An Ed25519 signature authorizes sensitive endpoints, such as withdrawals.
# API Changelog
Source: https://docs.anchorage.com/knowledge-base/api-reference/changelog
Subscribe to Anchorage API updates, additions, and breaking changes.
[2026](/knowledge-base/api-reference/changelog) · [2025](/knowledge-base/api-reference/changelog-2025) · [2024](/knowledge-base/api-reference/changelog-2024)
## Clarified `dateTime` Field in Transaction Responses
**Improved** The description for the `dateTime` field in transaction-related responses has been updated to clarify its meaning.
**Category**: Transactions
**Endpoints Affected**:
* `GET /transactions`
* `GET /transactions/{transactionId}`
**Impact**: The `dateTime` field now explicitly represents "The timestamp of when the transaction was created or when it reached its final state (completion or failure)." This provides more accurate context for transaction lifecycle tracking. No integration changes are required.
## Added Stablecoin Reserves Endpoints
**Added** two new endpoints to the Stablecoins API for retrieving reserve information.
**Category**: Stablecoins
**Endpoints Added**:
* `GET /stablecoins/reserves`: Retrieves the history of stablecoin reserves.
* `GET /stablecoins/reserves/entitled-stablecoins`: Gets a list of stablecoins for which the organization is entitled to view reserves.
**Impact**: These new endpoints allow users to programmatically access stablecoin reserve data and history.
## Improved Response Structure for the List Tags Endpoint
**Improved** The response body for the `GET /tags` endpoint now nests the list of tags within a `data` object for consistency with other API endpoints.
**Category**: Tagging
**Endpoint Changed**:
* `GET /tags`: Returns the list of tags nested under a `data` object instead of at the top level.
**Impact**: This is a breaking change. Integrations must be updated to read the list of tags from `response.data.tags` instead of the top-level `response.tags`.
**Example**:
*Previous Response Structure:*
```json theme={null}
{
"tags": [
{
"name": "urgent",
"tagType": "client"
}
]
}
```
*New Response Structure:*
```json theme={null}
{
"data": {
"tags": [
{
"name": "urgent",
"tagType": "client"
}
]
}
}
```
## Improved Field Naming for Creating Wallets on Compatible Networks
**Improved** The `createOnAllCompatibleNetworks` field for creating wallets has been renamed to `activateAllCompatibleNetworks`.
**Category**: Wallets
**Endpoint Changed**:
* `POST /vaults/{vaultId}/wallets`: The `createOnAllCompatibleNetworks` boolean property was removed and replaced by `activateAllCompatibleNetworks`.
**Impact**: This is a breaking change. Integrations using `createOnAllCompatibleNetworks` must switch to `activateAllCompatibleNetworks` to avoid request failures. The field's behavior is unchanged: when set to `true`, it activates the new wallet on every network that is key-compatible with the primary `networkId` and enabled for your organization.
## Improved Wallet Creation and Activation Across Compatible Networks
**Improved** wallet creation and activation to support all compatible networks with a single flag.
**Category**: Wallets
**Endpoints Changed**:
* `POST /vaults/{vaultId}/wallets`: Accepts a new optional boolean parameter, `createOnAllCompatibleNetworks`.
* `POST /wallets/{walletId}/activate`: Accepts a new optional boolean parameter, `activateAllCompatibleNetworks`.
**Impact**: This provides a more efficient way to manage wallets across multiple networks. Instead of listing every compatible network ID, you can use a single boolean flag to create or activate a wallet on all available compatible networks for your organization. The new `...AllCompatibleNetworks` parameters are mutually exclusive with the existing `compatibleNetworkIds` parameter, so you must provide exactly one of them.
## Added Endpoints for Tag Management
**Added** a new Tags API to create, list, and manage tags for entities.
**Category**: Tags
**Endpoints Added**:
* `GET /tags`: Lists tags.
* `POST /tags`: Creates a tag.
* `POST /tags/apply`: Applies tags to an entity.
* `DELETE /tags/apply/{entityId}/{tagName}`: Removes a tag from an entity.
* `GET /tags/search`: Searches for entities by tag.
**Impact**: This introduces a new feature for users to programmatically organize, categorize, and search for their resources using tags.
## Improved Asset Type Details with Compatible Network IDs
**Improved** The `GET /asset-types` endpoint response now includes a list of compatible network IDs.
**Category**: Asset Types
**Endpoint Changed**:
* `GET /asset-types`: The `AssetTypeDetails` object now contains `compatibleNetworkIds`, an array of network IDs that share wallet key derivation with the asset's primary network.
**Impact**: This helps you identify which networks can be used when creating a new wallet or activating an existing wallet on additional networks.
**Example**:
```json theme={null}
{
"data": [
{
"assetType": "ETH",
"name": "Ethereum",
"decimals": 18,
"networkId": "ETH",
"onchainIdentifier": null,
"featureSupport": [
"TRANSFERS",
"HOLDS"
],
"compatibleNetworkIds": [
"POLYGON",
"AVAX_C"
]
}
]
}
```
## Added Tax Lot Selection for Async Orders
**Added** the ability to specify a tax lot ID for async sell orders for tax reporting.
**Category**: Trading
**Endpoints Changed**:
* `POST /trading/async-order`: Accepts a new optional `specLotId` field to specify a tax lot to retire for `SELL` orders with a `timeInForce` of `FOK`; the `rejectReason` field in the response now includes `InvalidSideForSpecLotID` and `InvalidTimeInForceForSpecLotID`.
* `POST /trading/async-order/cancel`: The `rejectReason` field in the response now includes `InvalidSideForSpecLotID` and `InvalidTimeInForceForSpecLotID`.
**Impact**: You can now programmatically manage tax lot retirement for specific `SELL` orders, enhancing tax reporting capabilities.
## Improved Collateral Package Endpoint with Value and Price Details
**Improved** The response for the collateral packages endpoint now includes additional value and pricing details for each package and its underlying assets.
**Category**: Collateral Management
**Endpoint Changed**:
* `GET /collateral_management/packages`: The response now includes optional `exposureValue` and `packageValue` fields at the top level of each package, plus `price`, `quantity`, and `weightedValue` for each asset in the `collateralAssets` array.
**Impact**: This is a non-breaking change that gives you a more complete financial overview of each collateral package directly in the list view.
**Example**:
```json theme={null}
{
"data": [
{
"packageId": "unique-package-id",
"clientReferenceId": "client-ref-123",
"active": true,
"exposureValue": "50000.00",
"packageValue": "100000.00",
"collateralAssets": [
{
"asset": {
"assetType": "BTC",
"type": "ANCHORAGECUSTODY"
},
"price": "60000.00",
"quantity": "1.5",
"weight": "0.9",
"weightedValue": "81000.00"
}
],
// ... other fields
}
],
"page": {
"next": null
}
}
```
## Added Endpoint to Request Collateral Decrease
**Added** a new endpoint that lets users request a collateral decrease for a specified collateral package.
**Category**: Collateral Management
**Endpoint Added**:
* `POST /collateral_management/packages/{packageId}/collateral-decrease`: Initiates a two-way Atlas settlement to return assets from the secured party's collateral wallets to the pledgor's return wallets.
**Impact**: This lets either the pledgor or the secured party programmatically initiate the return of collateral assets. A successful call creates an Atlas settlement, and the `settlementId` is returned in the response for tracking.
**Example**:
```json theme={null}
{
"assetAmounts": [
{ "assetTypeID": "BTC", "value": "1.1" },
{ "assetTypeID": "ETH", "value": "20.62" }
],
"idempotencyKey": "decrease-2024-01-15-pkg-abc",
"useGasStation": false
}
```
## Added Endpoint to Activate Wallets on Additional Networks
**Added** a new endpoint to activate an existing wallet on additional compatible networks.
**Category**: Wallets
**Endpoint Added**:
* `POST /wallets/{walletId}/activate`: Activates an existing wallet on additional compatible networks.
**Impact**: This lets you enable a single wallet for use across multiple networks that share the same key family, streamlining asset management without needing to create separate wallets.
## Added Fiat Details to Transaction Responses
**Added** A new `fiatDetails` object is now included in transaction responses to provide banking details for fiat transactions.
**Category**: Transactions
**Endpoints Changed**:
* `GET /transactions`: The response now includes a `fiatDetails` object for fiat-related transactions.
* `GET /transactions/{transactionId}`: The response now includes a `fiatDetails` object for fiat-related transactions.
**Impact**: This provides key banking information, such as account number, bank name, and FedWire number, which aids in reconciliation and tracking.
**Example**:
```json theme={null}
"fiatDetails": {
"accountNumber": "123456789",
"bankId": "987654321",
"bankName": "Anchorage Digital Bank",
"fedWire": "WIRE12345",
"memo": "Q1 Payout",
"name": "Jane Doe"
}
```
## Added Endpoint to List All Subaccounts
**Added** a new endpoint to retrieve all subaccounts associated with an organization.
**Category**: Subaccounts
**Endpoint Added**:
* `GET /subaccounts/customers/accounts`: Lists all subaccounts for your organization, with filtering by `subaccountIds`, `externalIds`, `endDate`, and `statuses`, plus pagination via `afterId` and `limit`.
**Impact**: This provides a comprehensive, organization-level view of all subaccounts, enabling more efficient and complete data retrieval than fetching subaccounts on a per-customer basis.
## Improved Transfers and Withdrawals with Trusted Destination Support
**Improved** Transfers and withdrawals can now use a Trusted Destination as the destination, and wallet responses can reflect it as a resource type.
**Category**: Transfers, Transactions, Wallets
**Endpoints Changed**:
* `POST /transactions/withdrawal`: Accepts `TRUSTED_DESTINATION` as a `destination.type` value.
* `POST /transfers`: Accepts `TRUSTED_DESTINATION` as a `destination.type` value.
* `GET /transfers`: Can return `TRUSTED_DESTINATION` as a destination type in the response.
* `GET /transfers/{transferId}`: Can return `TRUSTED_DESTINATION` as a destination type in the response.
* `GET /vaults/{vaultId}/wallets`: Can return `TRUSTED_DESTINATION` as a wallet resource type.
* `POST /vaults/{vaultId}/wallets`: Can return `TRUSTED_DESTINATION` as a wallet resource type.
* `GET /wallets`: Can return `TRUSTED_DESTINATION` as a wallet resource type.
* `GET /wallets/{walletId}`: Can return `TRUSTED_DESTINATION` as a wallet resource type.
**Impact**: This simplifies withdrawal and transfer workflows. You can send funds to a pre-configured Trusted Destination by providing its ID, without needing to re-specify address details, memos, or destination tags in each API call. Using Trusted Destinations also reduces the risk of sending funds to an incorrect address.
**Example**:
```json theme={null}
{
"assetType": "XRP",
"amount": "100.00",
"source": {
"id": "1c920f4241b78a1d483a29f3c24b6c4c",
"type": "WALLET"
},
"destination": {
"id": "your_trusted_destination_id",
"type": "TRUSTED_DESTINATION"
}
}
```
## Removed Wallet Activation Endpoint
**Removed** The endpoint for activating an existing wallet on additional compatible networks has been removed.
**Category**: Wallets
**Endpoint Removed**:
* `POST /wallets/{walletId}/activate`
**Impact**: You can no longer programmatically activate an existing wallet on additional compatible networks.
## Added Endpoint to Activate Wallets on Additional Networks
**Added** a new endpoint to activate an existing wallet on additional compatible networks.
**Category**: Wallets
**Endpoint Added**:
* `POST /wallets/{walletId}/activate`: Activates an existing wallet on additional compatible networks that share the same key family, without creating a new wallet.
**Impact**: This lets you enable a single wallet for use across multiple networks that share the same key family, streamlining asset management by reusing a single wallet instead of creating a new one for each network.
## Added Endpoint for Collateral Decrease Requests
**Added** a new endpoint that lets users request a collateral decrease.
**Category**: Collateral Management
**Endpoint Added**:
* `POST /collateral_management/packages/{packageId}/collateral-decrease`: Enables programmatic requests to decrease collateral for a specified package.
**Impact**: This lets you programmatically initiate a decrease in collateral for a specific package.
## Added Compatible Networks Support to Wallet Creation
**Added** an optional `compatibleNetworkIds` field for activating a new wallet on additional compatible networks at the time of creation.
**Category**: Wallets
**Endpoint Changed**:
* `POST /vaults/{vaultId}/wallets`: Accepts a new optional `compatibleNetworkIds` field (an array of strings).
**Impact**: This lets you create a wallet and activate it on multiple compatible networks in a single API call. All specified networks must share the same key family as the primary `networkId`, and activation happens synchronously after wallet creation.
**Example**:
```json theme={null}
{
"networkId": "ETH",
"walletName": "My EVM Wallet",
"compatibleNetworkIds": [
"POLYGON",
"AVAX"
]
}
```
## Improved Memo Handling for Fiat Trusted Destinations
**Improved** The behavior of the `memo` field for fiat transfers and withdrawals to Trusted Destinations has been clarified.
**Category**: Transactions, Transfers, and Trusted Destinations
**Endpoints Changed**:
* `POST /transactions/withdrawal`: The `memo` field within `assetParametersFiatTrustedDestination` is now optional; if omitted, the default memo from the saved Trusted Destination is used.
* `POST /transfers`: The `memo` field within `assetParametersFiatTrustedDestination` is now optional; if omitted, the default memo from the saved Trusted Destination is used.
* `GET /trusted_destinations`: The response now specifies that the `memo` for a fiat destination has a maximum length of 140 characters.
**Impact**: This simplifies API calls by letting you rely on the pre-configured memo on a Trusted Destination, reducing the need to specify it in every withdrawal or transfer request.
## Improved Stablecoin History Response Field Naming
**Improved** In the response for the stablecoin history endpoint, the `issueRedeemId` field has been renamed to `id`.
**Category**: Stablecoins
**Endpoint Changed**:
* `GET /stablecoins/history`: The unique identifier for an issue or redeem operation is now returned as `id` instead of `issueRedeemId`.
**Impact**: This is a breaking change. Integrations that parse `issueRedeemId` must switch to the new `id` field.
**Example**:
*Before:*
```json theme={null}
{
"data": [
{
"issueRedeemId": "b1a1c1...",
"operationType": "ISSUE",
...
}
]
}
```
*After:*
```json theme={null}
{
"data": [
{
"id": "b1a1c1...",
"operationType": "ISSUE",
...
}
]
}
```
## Improved Stablecoin History Endpoint Pagination and Status Detail
**Improved** The stablecoin history response now aligns with the standard paginated format and includes more detailed status information.
**Category**: Stablecoins
**Endpoint Changed**:
* `GET /stablecoins/history`: The response now returns a `data` array plus a `page` object for pagination (replacing `hasNextPage`), adds `destinationOperationId` and `sourceOperationId`, adds a `status` field (`INITIATED`, `EXECUTING`, `COMPLETED`, `FAILED`, `UNKNOWN`), adds an optional `subStatus` field, and expands `operationType` to include `BRIDGE` and `SWAP`.
**Impact**: This is a breaking change. The `conversions` array is now nested under `data`, and pagination uses a `page.next` URL instead of the previous `hasNextPage` boolean. Integrations must be updated to parse the new response structure.
**Example**:
```json theme={null}
{
"data": [
{
"issueRedeemId": "...",
"operationType": "ISSUE",
"status": "COMPLETED",
"subStatus": null,
"sourceAssetTypeId": "USD",
"destinationAssetTypeId": "USDC",
"amount": "100.00",
"sourceOperationId": "...",
"destinationOperationId": "..."
}
],
"page": {
"next": "/v2/stablecoins/history?..."
}
}
```
## Improved Order Type Support with LIMIT\_ALL\_IN
**Improved** Added `LIMIT_ALL_IN` as a new possible enum value for the `orderType` field in trading order responses.
**Category**: Trading
**Endpoints Changed**:
* `GET /trading/orders`: The `orderType` field in the response may now include `LIMIT_ALL_IN`.
* `GET /trading/orders/{orderId}`: The `orderType` field in the response may now include `LIMIT_ALL_IN`.
**Impact**: Responses from the list orders and get order by ID endpoints may now include `LIMIT_ALL_IN` as an `orderType`. Make sure your client can handle this new value.
## Improved Statements with Correction Timestamps and Filtering
**Improved** Added filtering and timestamp information for corrected statements, so you can track and query statements updated after their initial generation.
**Category**: Statements
**Endpoints Changed**:
* `GET /statements`: Accepts two new optional query parameters, `correctedAfter` and `correctedBefore`, to filter for statements corrected at or after or before a given time.
* `GET /statements/{statementId}`: The response now includes a `correctedAt` field indicating when a correction was made.
**Impact**: You can now programmatically identify and filter for statements that have been corrected, improving audit and reconciliation workflows.
**Example**:
```json theme={null}
{
"data": {
"customerId": "fbcdb420fca4439d919089e60d59cd5b12b692d215694681b636bffb6cb1618c",
"createdAt": "2025-09-01T00:47:16.937934Z",
"correctedAt": "2025-09-15T10:00:00.000000Z",
"displayName": "ETF Statement September 2025",
"id": "8de0fc33-7443-4dcf-bbf1-4ca8d0e0509f",
"typeId": "058da362-31a7-4e2b-ae3e-77b095389a5f"
}
}
```
## Added Subaccount ID Filter for Deposit Attributions
**Added** You can now filter deposit attributions by one or more `subaccountIds`.
**Category**: Deposit Attribution
**Endpoint Changed**:
* `GET /deposit-attributions/attributions`: Accepts a new query parameter, `subaccountIds`.
**Impact**: This allows for more granular filtering of deposit attributions, making it easier to retrieve records associated with specific subaccounts.
**Example**: `GET /v2/deposit-attributions/attributions?subaccountIds=subaccount_id_1,subaccount_id_2`
## Improved Permission Requirements for Stablecoin History
**Improved** permission requirements for the stablecoin history endpoint.
**Category**: Stablecoins
**Endpoint Changed**:
* `GET /stablecoins/history`: Now uses the more specific `Read Stablecoin Conversions` permission as the primary requirement.
**Impact**: For backward compatibility, the endpoint continues to accept the older `Read vault activity` permission too, so no immediate changes are required for existing integrations.
## Added Stablecoin Conversion History Endpoint
**Added** a new endpoint to retrieve the history of stablecoin issuance and redemption operations.
**Category**: Stablecoins
**Endpoint Added**:
* `GET /stablecoins/history`: Returns a historical list of your stablecoin issuance and redemption operations.
**Impact**: You can now programmatically access your stablecoin conversion history for tracking and reporting purposes.
## Added Binance as a Price Source for Collateral Management
**Added** support for `BINANCE` as a price source in Collateral Management.
**Category**: Collateral Management
**Endpoints Changed**:
* `GET /collateral_management/price_sources`: Now returns `BINANCE` as an available source and accepts it as a filter in the `exchange` query parameter.
* `POST /collateral_management/packages`: The `priceSource` field now accepts `BINANCE`.
* `PATCH /collateral_management/packages/{packageId}`: The `priceSource` field now accepts `BINANCE`.
* `POST /collateral_management/exposures`: The `priceSource` field now accepts `BINANCE`.
**Impact**: This allows for more flexible pricing options when creating and managing collateral packages and exposures.
**Example**:
```json theme={null}
"collateralAssetsConfig": [
{
"asset": {
"assetType": "BTC",
"type": "ANCHORAGECUSTODY"
},
"priceSource": "BINANCE",
"weight": "1.0",
"liquidationPriority": 1
}
]
```
## Added Accelerated Margin Call for Collateral Management
**Added** A new `acceleratedMarginCall` configuration level for collateral packages, letting you set an additional margin call threshold with its own LTV, cure period, and action.
**Category**: Collateral Management
**Endpoints Changed**:
* `POST /collateral_management/packages`: Accepts a new `acceleratedMarginCall` object in the request body.
* `PATCH /collateral_management/packages/{packageId}`: Accepts a new `acceleratedMarginCall` object in the request body.
* `GET /collateral_management/packages`: The response now includes the `acceleratedMarginCall` object.
**Impact**: You can now define and monitor an additional, accelerated margin call level for your collateral packages, providing more granular risk management.
## Removed TRUSTED\_DESTINATION Resource Type from Transfers and Wallets
**Removed** The `TRUSTED_DESTINATION` enum value from the `destination.type` field for transfer and withdrawal requests, and from the `type` field in several Wallet and Transfer responses.
**Category**: Transfers, Transactions, and Wallets
**Endpoints Changed**:
* `POST /transactions/withdrawal`: `destination.type` no longer accepts `TRUSTED_DESTINATION`; the `assetParametersATOM` field is now deprecated in favor of `assetParametersCosmos`.
* `POST /transfers`: `destination.type` no longer accepts `TRUSTED_DESTINATION`; the `assetParametersATOM` field is now deprecated in favor of `assetParametersCosmos`.
* `GET /transfers`: The `type` field in responses no longer returns `TRUSTED_DESTINATION`.
* `GET /transfers/{transferId}`: The `type` field in responses no longer returns `TRUSTED_DESTINATION`.
* `GET /vaults/{vaultId}/wallets`: The `type` field in responses no longer returns `TRUSTED_DESTINATION`.
* `POST /vaults/{vaultId}/wallets`: The `type` field in responses no longer returns `TRUSTED_DESTINATION`.
* `GET /wallets`: The `type` field in responses no longer returns `TRUSTED_DESTINATION`.
* `GET /wallets/{walletId}`: The `type` field in responses no longer returns `TRUSTED_DESTINATION`.
**Impact**: This is a breaking change. Requests that specify `destination.type` as `TRUSTED_DESTINATION` will now fail. To send funds to a trusted destination, use `destination.type: 'ADDRESS'` with the specific blockchain address, and update any logic that parses the `type` field in Wallet and Transfer responses. Users are encouraged to migrate from the deprecated `assetParametersATOM` to `assetParametersCosmos`.
## Improved Order Filtering Parameter Description
**Improved** the description for the `orderTypes` query parameter to enhance clarity.
**Category**: Trading
**Endpoint Changed**:
* `GET /trading/orders`: The description for the `orderTypes` parameter was updated.
**Impact**: This is a non-breaking documentation change. No integration updates are required.
## Improved Statement Filtering and Response Structure
**Improved** the Statements endpoints with updated filtering parameters and a restructured response body.
**Category**: Statements
**Endpoints Changed**:
* `GET /statements`: Removed the `statementIds`, `statementTypes`, `accountIds`, `affiliateIds`, `vaultGroupIds`, and `subaccountIds` filter parameters, and added `ids`, `typeIds`, and `customerIds`. The response no longer includes `accountId`, `affiliateId`, `subaccountId`, `vaultGroupId`, or the required `type` field, and now includes `customerId` and the new required `typeId` field (`type` is now optional).
* `GET /statements/{statementId}`: The response no longer includes `accountId`, `affiliateId`, `subaccountId`, `vaultGroupId`, or the required `type` field, and now includes `customerId` and the new required `typeId` field (`type` is now optional).
**Impact**: This is a breaking change. Integrations using the `/statements` endpoints must be updated to use the new query parameters and handle the modified response structure.
## Improved Order Type Support with MANUAL
**Improved** Added support for a new `MANUAL` order type.
**Category**: Trading
**Endpoints Changed**:
* `GET /trading/orders`: The `orderType` field in the response can now include `MANUAL`.
* `GET /trading/orders/{orderId}`: The `orderType` field in the response can now include `MANUAL`.
**Impact**: Clients should update their integrations to handle this new enum value when listing or retrieving orders.
## Improved Fiat Trusted Destination Response Structure
**Improved** The structure of the `fiat` object in the trusted destinations response has been refactored for clarity, with beneficiary and financial institution details now grouped into nested `beneficiary` and `beneficiaryBank` objects, plus new `intermediaryBank` and `usage` fields.
**Category**: Trusted Destinations
**Endpoint Changed**:
* `GET /trusted_destinations`: The `fiat` object's flat beneficiary and institution properties are now nested under `beneficiary` and `beneficiaryBank`, and the object gains `intermediaryBank` and `usage` fields.
**Impact**: This is a breaking change. Integrations that parsed the flat properties within the `fiat` object must be updated to handle the new nested structure. The new `usage` field indicates whether the recipient account is owned by your organization or a third party.
**Example**:
*Before:*
```json theme={null}
{
"fiat": {
"beneficiaryName": "Satoshi Nakamoto",
"beneficiaryAccount": "*****1234",
"institutionName": "The Bank of New York Mellon",
"institutionId": "IRVTUS3N",
//... other flat properties
}
}
```
*After:*
```json theme={null}
{
"fiat": {
"beneficiary": {
"name": "Satoshi Nakamoto",
"account": "*****1234",
//... other beneficiary properties
},
"beneficiaryBank": {
"name": "The Bank of New York Mellon",
"id": "IRVTUS3N",
//... other bank properties
},
"intermediaryBank": {},
"usage": "MY_ORGANIZATION"
}
}
```
## Added Fiat Support for Trusted Destinations
**Added** support for fiat (bank account) trusted destinations.
**Category**: Trusted Destinations
**Endpoint Changed**:
* `GET /trusted_destinations`: The response now includes details for fiat-based trusted destinations.
**Impact**: When listing trusted destinations, a fiat destination now has a `type` of `fiat` and contains a new `fiat` object with detailed bank account information.
**Example**:
```json theme={null}
{
"data": [
{
"id": "td_fiat_12345",
"name": "Corporate Bank Account",
"description": "Primary USD account",
"type": "fiat",
"owner": {
"id": "customer_abc",
"type": "CUSTOMER"
},
"fiat": {
"beneficiaryName": "Example Corp",
"beneficiaryAccount": "987654321",
"beneficiaryType": "BUSINESS",
"institutionName": "Example Bank",
"institutionId": "121000358",
"institutionCode": "ABA",
"memo": "For operating expenses"
},
"crypto": null
}
]
}
```
## Improved Order Allocation Details with Filled Quantity
**Improved** The `allocation` object in trading order responses now includes the `cumQty` field, which specifies the filled quantity for each subaccount allocation.
**Category**: Trading
**Endpoints Changed**:
* `POST /trading/order`: The `allocation` object in the response now includes the required `cumQty` field.
* `GET /trading/orders`: The `allocation` object in the response now includes the required `cumQty` field.
* `GET /trading/orders/{orderId}`: The `allocation` object in the response now includes the required `cumQty` field.
* `POST /trading/async-order`: The `allocation` object in the response now includes the required `cumQty` field.
* `POST /trading/async-order/cancel`: The `allocation` object in the response now includes the required `cumQty` field.
**Impact**: This is a non-breaking change that provides more granular data on order fills at the subaccount level.
**Example**:
```json theme={null}
"allocation": [
{
"subaccountId": "905272f0-52f9-404e-b6cd-ad879e671790",
"quantity": "10000",
"cumQty": "10000",
"counterQtyAllIn": "10000",
"counterQtyAllInToSettle": "10000",
"fee": "10000"
}
]
```
## Improved Collateral Management Price Sources Endpoint
**Improved** Added a new `501 Not Implemented` response and clarified the `exchange` query parameter description.
**Category**: Collateral Management
**Endpoint Changed**:
* `GET /collateral_management/price_sources`: Now returns a `501 Not Implemented` error if the price sources feature is disabled; the `exchange` parameter description was simplified.
**Impact**: API consumers will now receive a `501 Not Implemented` error if the price sources feature is disabled.
## Improved Clarity for Tax Reporting Deposit Transaction Endpoints
**Improved** descriptions for the Tax Reporting endpoints to clarify that cost basis management applies specifically to deposit transactions.
**Category**: Tax Reporting
**Endpoints Changed**:
* `PATCH /tax/accounts/{accountId}/transactions/{transactionId}`: The endpoint and `hasCostBasis` parameter descriptions were improved for accuracy.
* `GET /tax/accounts/{accountId}/transactions`: The endpoint and `hasCostBasis` parameter descriptions were improved for accuracy.
**Impact**: This is a documentation-only change to improve clarity. The functionality of the endpoints remains unchanged.
## Improved Async Order Responses with Counter Currency Details
**Improved** Added `counterCurrency`, `counterQty`, and `counterQtyAllIn` fields to the responses for placing and canceling async orders.
**Category**: Trading
**Endpoints Changed**:
* `POST /trading/async-order`: The response now includes `counterCurrency`, `counterQty`, and `counterQtyAllIn`.
* `POST /trading/async-order/cancel`: The response now includes `counterCurrency`, `counterQty`, and `counterQtyAllIn`.
**Impact**: The responses for placing and canceling an async order now include the counter currency, the filled quantity of the counter currency, and the filled quantity including all fees.
**Example**:
```json theme={null}
{
"data": {
"clOrderId": "6fb5fc79-0bb4-446d-82dd-d4687fb56a02",
"orderId": "a94c8d75-6c9d-4903-95f3-5b0893e76cb7",
// ... existing fields
"counterCurrency": "BTC",
"counterQty": "0.4760680586896702",
"counterQtyAllIn": "0.4760544606302961",
"transactTime": "2023-03-12T22:22:09.925050Z"
}
}
```
## Added Collateral Management Price Sources Endpoint
**Added** a new endpoint to get available price sources and their supported assets.
**Category**: Collateral Management
**Endpoint Added**:
* `GET /collateral_management/price_sources`: Returns supported price sources and the specific assets available for each source.
**Impact**: This lets clients programmatically retrieve supported price sources, which can be used to validate configurations for collateral packages.
## Improved Price Strategy Options for Collateral Management
**Improved** The `priceStrategy` options for creating and managing collateral packages and exposures now include `MID` and `LAST`; `VWAP` has been removed.
**Category**: Collateral Management
**Endpoints Changed**:
* `POST /collateral_management/packages`: The `priceStrategy` field now accepts `MID` and `LAST`; `VWAP` is no longer supported.
* `PATCH /collateral_management/packages/{packageId}`: The `priceStrategy` field now accepts `MID` and `LAST`; `VWAP` is no longer supported.
* `POST /collateral_management/exposures`: The `priceStrategy` field now accepts `MID` and `LAST`; `VWAP` is no longer supported.
**Impact**: This is a breaking change. Integrations using the `priceStrategy` field must switch from `VWAP` to `MID` or `LAST`.
## Added Fiat Parameters for Trusted Destination Transfers and Withdrawals
**Added** A new `assetParametersFiatTrustedDestination` object to the request body for fiat transfers and withdrawals to Trusted Destinations.
**Category**: Transactions, Transfers
**Endpoints Changed**:
* `POST /transactions/withdrawal`: Accepts a new optional `assetParametersFiatTrustedDestination` object with `memo` and `purpose` fields.
* `POST /transfers`: Accepts a new optional `assetParametersFiatTrustedDestination` object with `memo` and `purpose` fields.
**Impact**: This lets you provide additional context when sending fiat assets to a Trusted Destination, which is useful for record-keeping and compliance.
**Example**:
```json theme={null}
{
"assetType": "USD",
"amount": "5000.00",
"source": {
"id": "1c920f4241b78a1d483a29f3c24b6c4c",
"type": "WALLET"
},
"destination": {
"id": "td_123abc...",
"type": "TRUSTED_DESTINATION"
},
"assetParametersFiatTrustedDestination": {
"memo": "Q1 Payout",
"purpose": "INVESTMENT"
},
"idempotentId": "unique-withdrawal-id-123"
}
```
## Improved Offchain Vesting Schedule Response with Asset Type
**Improved** the response for listing offchain vesting schedules to include the asset type.
**Category**: Vesting
**Endpoint Changed**:
* `GET /offchainvesting/schedules`: Each schedule object in the `data` array now includes the `assetType` field, specifying the asset abbreviation (for example, BTC or ETH).
**Impact**: This is a non-breaking, additive change that makes it easier to identify the asset associated with each vesting schedule directly from the list endpoint.
## Improved Transfers and Withdrawals with Trusted Destinations
**Improved** You can now use pre-configured Trusted Destinations when creating transfers and withdrawals, sending funds to a `TRUSTED_DESTINATION` ID instead of a full address.
**Category**: Transfers & Withdrawals
**Endpoints Changed**:
* `POST /transfers`: The `destination.type` field now accepts `TRUSTED_DESTINATION`.
* `POST /transactions/withdrawal`: The `destination.type` field now accepts `TRUSTED_DESTINATION`.
* `GET /transfers`: The response can now reflect `TRUSTED_DESTINATION` as a destination type.
* `GET /transfers/{transferId}`: The response can now reflect `TRUSTED_DESTINATION` as a destination type.
**Impact**: When sending to a `TRUSTED_DESTINATION`, you no longer need to include asset-specific parameters like `assetParametersXRP` or `assetParametersXLM` — the destination tag or memo is inherited automatically from the trusted destination's configuration.
**Example**:
```json theme={null}
// POST /transactions/withdrawal
{
"assetType": "XRP",
"amount": "100.0",
"source": {
"id": "your_wallet_id",
"type": "WALLET"
},
"destination": {
"id": "your_trusted_destination_id",
"type": "TRUSTED_DESTINATION"
},
"idempotentId": "unique-id-for-withdrawal-123"
}
```
## Improved Market Data Endpoint with Amount-Based Depth
**Improved** The market data endpoint now supports returning market depth by notional value, such as USD, in addition to asset size.
**Category**: Trading
**Endpoint Changed**:
* `GET /trading/marketdata`: A new `amount` field has been added to the `bids` and `offers` objects, returned when using the `amountBuckets` query parameter; the existing `size` field is returned when using `sizeBuckets`.
**Impact**: This is a non-breaking change that lets you request market depth in notional terms instead of, or alongside, asset size.
**Example**:
```json theme={null}
// Request using amountBuckets
GET /trading/marketdata?symbol=BTC-USD&amountBuckets=10000,50000
// Sample Response Snippet
"bids": [
{
"price": "65000.00",
"amount": "10000.00" // New field: value in USD
},
{
"price": "64950.00",
"amount": "50000.00" // New field: value in USD
}
]
```
## Added Endpoint to Propose Trusted Counterparties
**Added** A new endpoint to propose a new trusted counterparty.
**Category**: Atlas Settlement Network
**Endpoint Added**:
* `POST /atlas/directory/counterparties`: Proposes a new trusted counterparty.
**Impact**: You can now programmatically propose new trusted counterparties, streamlining the process of adding new settlement partners.
## Improved Market Data Parameter Descriptions
**Improved** descriptions for the `sizeBuckets` and `amountBuckets` query parameters to clarify their usage and impact on the response.
**Category**: Trading
**Endpoint Changed**:
* `GET /trading/marketdata`: `sizeBuckets` is clarified as a comma-separated list; `amountBuckets` is clarified as a comma-separated list of USD values, with a note that using it affects how `size` is represented in the response.
**Impact**: This is a non-breaking documentation change that provides better guidance for querying market depth.
## Improved Cost Basis Reporting with Tax Lots
**Improved** the Tax Reporting endpoints to support lot-level cost basis management for more granular and accurate tax data.
**Category**: Tax Reporting
**Endpoints Changed**:
* `PATCH /tax/accounts/{accountId}/transactions/{transactionId}`: The request body now requires a `lots` array (each with `lotId`, `quantity`, and `costBasis`) in place of the previous `data`, `acquisitionDatetime`, and `assetType` fields.
* `GET /tax/accounts/{accountId}/transactions`: The response now includes a required top-level `assetType` field per transaction, and an `acquisitionDatetime` field on each lot in the `receivedAssets` array.
**Impact**: This moves cost basis reporting from a per-transaction model to a per-lot model, letting you specify and retrieve cost basis information for individual lots within a single transaction.
## Added Market Data Endpoint
**Added** a new endpoint to retrieve a snapshot of market data.
**Category**: Trading
**Endpoint Added**:
* `GET /trading/marketdata`: Returns a snapshot of current market data.
**Impact**: You can now programmatically access market data for pricing, analysis, and other trading-related activities. See the [Market Data Guide](https://developers.anchorage.com/docs/websocket-api-market-data) for more information.
## Improved Transaction Types and Settlement Parameter Documentation
**Improved** Added the `FIAT_INTEREST` transaction type and clarified the `applyPostLock` parameter description.
**Category**: Transactions, Atlas Settlement Network
**Endpoints Changed**:
* `GET /transactions`: The `transactionType` field in the response can now include `FIAT_INTEREST`, representing fiat interest payments.
* `GET /transactions/{transactionId}`: The `transactionType` field in the response can now include `FIAT_INTEREST`, representing fiat interest payments.
* `POST /atlas/settlements`: The description for the `applyPostLock` parameter now clarifies it applies only to clients using Atlas settlements integrated with Anchorage Vesting.
**Impact**: Clients should update their systems to handle the new `FIAT_INTEREST` transaction type. The `applyPostLock` documentation change is non-breaking and only clarifies existing behavior.
## Deprecated `totalDistribution` Field in Tax Tagging
**Deprecated** the `totalDistribution` field for tagging tax transactions.
**Category**: Tax
**Endpoint Changed**:
* `POST /tax/transaction/{transactionId}/tag`: The `totalDistribution` field in the request body is now deprecated and ignored if provided.
**Impact**: Any value passed in `totalDistribution` is disregarded — total distribution status is now calculated automatically from account balances. Remove this field from your requests, since it no longer has any effect.
## Added Post-Settlement Locking for Atlas Settlements
**Added** a new `applyPostLock` parameter to automatically create post-settlement holds on funds received through the Atlas Settlement Network.
**Category**: Atlas Settlement Network
**Endpoint Changed**:
* `POST /atlas/settlements`: Accepts a new optional boolean `applyPostLock` parameter; when `true`, indefinite holds are placed on the acceptor's destination wallets after a successful settlement.
**Impact**: This enables the automatic creation of post-settlement vesting schedules on received funds, streamlining workflows that require funds to be locked after settlement.
## Added Vesting Schedules Endpoint and Tax Transaction Cost Basis Filter
**Added** a new endpoint for listing offchain vesting schedules and a new filter for tax transactions.
**Category**: Vesting, Tax Reporting
**Endpoints Changed**:
* `GET /offchainvesting/schedules`: New endpoint that lists all offchain vesting schedules for your organization.
* `GET /tax/accounts/{accountId}/transactions`: Accepts a new `hasCostBasis` query parameter to filter transactions that do or don't have a cost basis.
**Impact**: This provides programmatic access to vesting schedules and lets you filter tax transactions by whether they have a cost basis, improving transparency and reporting.
## Improved Transaction Types with Priority Fee Reward
**Improved** The `transactionType` field in transaction-related endpoints now includes `PRIORITY_FEE_REWARD` to represent priority fee rewards.
**Category**: Transactions
**Endpoints Changed**:
* `GET /transactions`: The `transactionType` field in the response can now include `PRIORITY_FEE_REWARD`.
* `GET /transactions/{transactionId}`: The `transactionType` field in the response can now include `PRIORITY_FEE_REWARD`.
**Impact**: This new type identifies priority fee rewards, such as those from Jito priority fee distributions on Solana.
## Improved Clarity for Trusted Destination Asset Type
**Improved** The description for the `assetType` field has been updated to provide better clarity when creating a trusted destination.
**Category**: Trusted Destinations
**Endpoint Changed**:
* `POST /trusted_destinations`: The description for `assetType` in the `trustedDestinations` array now clarifies what an asset type is and points to `GET /asset-types` for a list of supported types.
**Impact**: This is a non-breaking documentation change. The endpoint's functionality remains the same.
## Improved Security with Signature Requirements for Collateral Management
**Improved** security by requiring `Api-Signature` and `Api-Timestamp` headers for write operations on Collateral Management endpoints.
**Category**: Collateral Management
**Endpoints Changed**:
* `PATCH /collateral_management/operations/{operationId}`: Now requires `Api-Signature` and `Api-Timestamp` headers.
* `PATCH /collateral_management/packages/{packageId}`: Now requires `Api-Signature` and `Api-Timestamp` headers.
* `POST /collateral_management/exposures`: Now requires `Api-Signature` and `Api-Timestamp` headers.
* `POST /collateral_management/operations`: Now requires `Api-Signature` and `Api-Timestamp` headers.
* `POST /collateral_management/packages`: Now requires `Api-Signature` and `Api-Timestamp` headers.
**Impact**: This is a breaking change. Requests to these endpoints will now fail if they don't include valid signature and timestamp headers. See the Request Signatures section of the documentation for instructions on generating a valid signature.
## Improved Wallet Responses with Unvested and Unstakeable Balances
**Improved** Wallet-related endpoints now include more detailed balance information for offchain vesting.
**Category**: Wallets
**Endpoints Changed**:
* `GET /vaults/{vaultId}/wallets`: The `assets` object now includes `unvestedBalance` and `unvestedUnstakeableBalance` fields.
* `POST /vaults/{vaultId}/wallets`: The `assets` object now includes `unvestedBalance` and `unvestedUnstakeableBalance` fields.
* `GET /wallets`: The `assets` object now includes `unvestedBalance` and `unvestedUnstakeableBalance` fields.
* `GET /wallets/{walletId}`: The `assets` object now includes `unvestedBalance` and `unvestedUnstakeableBalance` fields.
**Impact**: This is a non-breaking change. Responses now contain additional balance details for assets in offchain vesting contracts, where applicable.
## Improved Vesting Balance Retrieval for Multiple Allocations
**Improved** vesting balance retrieval by adding a new endpoint to fetch balances for multiple allocations in a single request.
**Category**: Vesting
**Endpoint Added**:
* `POST /vesting/balances`: Retrieves vesting balances for multiple allocations in a single request.
**Impact**: This allows for more efficient retrieval of balance data by fetching information for multiple allocations at once, reducing the number of required API calls.
## Improved Security with Request Signing for Atlas Settlement Endpoints
**Improved** security by adding request signing to key Atlas Settlement Network endpoints, which now require `Api-Signature` and `Api-Timestamp` headers.
**Category**: Atlas Settlement Network
**Endpoints Changed**:
* `POST /atlas/settlements`: Now requires `Api-Signature` and `Api-Timestamp` headers.
* `POST /atlas/settlements/{settlementId}/accept`: Now requires `Api-Signature` and `Api-Timestamp` headers.
* `POST /atlas/settlements/{settlementId}/authorize`: Now requires `Api-Signature` and `Api-Timestamp` headers.
* `POST /atlas/settlements/{settlementId}/reject`: Now requires `Api-Signature` and `Api-Timestamp` headers.
**Impact**: This is a breaking change. Requests made to the listed endpoints will now fail if they don't include the required signature headers. See the Request Signatures section of the documentation for instructions on generating the required signatures.
## Improved Stablecoin Conversion Documentation
**Improved** the description for the `sourceAssetType` field in the stablecoin conversion request body for clarity.
**Category**: Stablecoins
**Endpoint Changed**:
* `POST /stablecoins/conversion`: The `sourceAssetType` description now clarifies that it must be `USD` for an issuance, and the asset being redeemed for a redemption.
**Impact**: This is a non-breaking documentation change.
## Improved Staking Request Descriptions
**Improved** The descriptions for the `parameters` object and the `stakingProviderAddress` field for Solana staking requests have been updated for clarity.
**Category**: Transactions
**Endpoint Changed**:
* `POST /transactions/stake`: The description for the `parameters` object was updated, and within `SOLStakingParameters`, `stakingProviderAddress` now describes "the validator's vote account address" instead of "the validator's staking address".
**Impact**: This is a non-breaking documentation change to provide better clarity for clients creating Solana (SOL) staking requests.
## Added Endpoint for Consolidating Stakes
**Added** a new endpoint to create a consolidate stake request.
**Category**: Transactions
**Endpoint Added**:
* `POST /transactions/consolidate-stake`: Initiates a request to consolidate staking positions.
**Impact**: This feature enhances staking management by allowing users to consolidate stakes directly through the API. See the [staking guide](https://developers.anchorage.com/docs/ethereum-pectra-staking-api#consolidate-pectra-to-pectra-validator) for instructions on use.
## Improved Backward Compatibility by Re-introducing the VAULT Resource Type
**Improved** backward compatibility by re-introducing the `VAULT` enum value for source and destination resources; it's accepted but deprecated in favor of `WALLET`.
**Category**: Transfers, Wallets, and Transactions
**Endpoints Changed**:
* `POST /transactions/withdrawal`: Accepts `VAULT` again as a resource type, though deprecated in favor of `WALLET`.
* `POST /transfers`: Accepts `VAULT` again as a resource type, though deprecated in favor of `WALLET`.
* `GET /transfers`: Accepts `VAULT` again as a resource type, though deprecated in favor of `WALLET`.
* `GET /transfers/{transferId}`: Accepts `VAULT` again as a resource type, though deprecated in favor of `WALLET`.
* `GET /vaults/{vaultId}/wallets`: Accepts `VAULT` again as a resource type, though deprecated in favor of `WALLET`.
* `POST /vaults/{vaultId}/wallets`: Accepts `VAULT` again as a resource type, though deprecated in favor of `WALLET`.
* `GET /wallets`: Accepts `VAULT` again as a resource type, though deprecated in favor of `WALLET`.
* `GET /wallets/{walletId}`: Accepts `VAULT` again as a resource type, though deprecated in favor of `WALLET`.
**Impact**: This restores backward compatibility for integrations still using the `VAULT` resource type. We strongly recommend updating existing code to use `WALLET` instead, since support for `VAULT` will be removed in a future release.
## Fixed AML Questionnaire Requirement by Organization Type
**Fixed** The `trustedDestinationAmlQuestionnaire` field is now conditionally required based on the organization type.
**Category**: Trusted Destinations
**Endpoint Changed**:
* `POST /trusted_destinations`: The `trustedDestinationAmlQuestionnaire` field is now required for Anchorage Digital organizations and must be omitted for Porto organizations.
**Impact**: Requests to create a trusted destination will now fail if `trustedDestinationAmlQuestionnaire` is included for a Porto organization or omitted for an Anchorage Digital organization.
## Added Endpoints for Tax Account Management
**Added** new endpoints to the Tax API for managing tax accounts and their associated transactions.
**Category**: Tax
**Endpoints Added**:
* `GET /tax/accounts`: Lists tax accounts.
* `GET /tax/accounts/{accountId}/transactions`: Retrieves transactions for a specific tax account.
* `PATCH /tax/accounts/{accountId}/transactions/{transactionId}`: Updates the cost basis of a transaction for tax reporting.
**Impact**: These new endpoints let you list tax accounts, retrieve transactions for a specific account, and update the cost basis of a transaction for tax reporting purposes.
## Removed TRUSTED\_DESTINATION as a Resource Type
**Removed** The `TRUSTED_DESTINATION` value as a valid enum for the resource `type` field.
**Category**: Transfers, Withdrawals, Wallets
**Endpoints Changed**:
* `POST /transactions/withdrawal`: The `destination.type` field no longer accepts `TRUSTED_DESTINATION`.
* `POST /transfers`: The `destination.type` field no longer accepts `TRUSTED_DESTINATION`.
* `GET /transfers`: The `type` field in responses no longer returns `TRUSTED_DESTINATION`.
* `GET /transfers/{transferId}`: The `type` field in responses no longer returns `TRUSTED_DESTINATION`.
* `GET /vaults/{vaultId}/wallets`: The `type` field in responses no longer returns `TRUSTED_DESTINATION`.
* `POST /vaults/{vaultId}/wallets`: The `type` field in responses no longer returns `TRUSTED_DESTINATION`.
* `GET /wallets`: The `type` field in responses no longer returns `TRUSTED_DESTINATION`.
* `GET /wallets/{walletId}`: The `type` field in responses no longer returns `TRUSTED_DESTINATION`.
**Impact**: This is a breaking change. API calls using `destination.type: TRUSTED_DESTINATION` will now fail. Specify the underlying `ADDRESS` or `WALLET` directly when creating transfers or withdrawals.
## Improved Tax Transaction Tagging with IRS Combination Codes
**Improved** The `distributionCode` field for tagging tax transactions now supports IRS combination codes.
**Category**: Tax
**Endpoint Changed**:
* `POST /tax/transaction/{transactionId}/tag`: The `distributionCode` field now accepts combination codes (for example, `1B`, `4G`, `7B`) as valid enum values.
**Impact**: This allows for more accurate tax reporting when a distribution has multiple applicable IRS classifications, such as using `4G` for a death-related direct rollover.
## Improved Collateral Management Operations with Liquidation Details
**Improved** The response for Collateral Management Operations now includes liquidation details and an update timestamp.
**Category**: Collateral Management
**Endpoints Changed**:
* `PATCH /collateral_management/operations/{operationId}`: The `CMOperation` model now includes `updatedAt`, `liquidationCollateralPackageId`, `liquidationProceedAsset`, and `liquidationProceedQuantity`.
* `GET /collateral_management/operations`: The `CMOperation` model now includes `updatedAt`, `liquidationCollateralPackageId`, `liquidationProceedAsset`, and `liquidationProceedQuantity`.
**Impact**: This provides more comprehensive data on operations, particularly those involving liquidations.
## Improved API Key Info Response with WRITE\_TAX Permission
**Improved** Added the new `WRITE_TAX` permission type, which now appears in the response for the get API key info endpoint.
**Category**: API Key
**Endpoint Changed**:
* `GET /apikey`: The `permissions` array in the response now includes `WRITE_TAX` for API keys that have this permission.
**Impact**: This is a non-breaking change.
**Example**:
```json theme={null}
{
"data": {
"id": "b5a58566763e77e2d87a53463013981be7c0b048c1c0dd39ba44e77c99bc1351",
"permissions": [
{
"permission": "READ",
"vaultIds": [
"1c920f4241b78a1d483a29f3c24b6c4c"
]
},
{
"permission": "WRITE_TAX"
}
]
}
}
```
## Added AML Questionnaire to Trusted Destination Creation
**Added** an optional `trustedDestinationAmlQuestionnaire` object to the request body for creating trusted destinations, so Anti-Money Laundering information can be submitted upfront.
**Category**: Trusted Destinations
**Endpoint Changed**:
* `POST /trusted_destinations`: Accepts an optional `trustedDestinationAmlQuestionnaire` object within each item of the `trustedDestinations` array.
**Impact**: This is a non-breaking change. Providing AML information when creating a trusted destination can streamline the approval process for future withdrawals to that address.
**Example**:
```json theme={null}
{
"idempotentId": "1ca86e65-4340-4876-85f4-8334852b9c43",
"owner": {
"type": "CUSTOMER",
"id": "your-customer-id"
},
"trustedDestinations": [
{
"assetType": "BTC",
"address": "2N19AcihQ1a4MxQW658UFHTioUNnMkiHPkw",
"name": "My Exchange Wallet",
"description": "BTC wallet at Example Exchange",
"trustedDestinationAmlQuestionnaire": {
"destinationType": "FINANCIAL_INSTITUTION",
"institutionName": "Example Exchange",
"institutionCountry": "US",
"recipientType": "DESTINATION_INSTITUTION"
}
}
]
}
```
## Improved Deposit Address Security with V2 Signatures
**Improved** security by introducing a V2 signature scheme for deposit addresses.
**Category**: Addresses, Wallets
**Endpoints Changed**:
* `GET /vaults/{vaultId}/addresses`: Signed address responses can now include `signatureVersion` and `certChain` fields.
* `POST /wallets/{walletId}/addresses`: Signed address responses can now include `signatureVersion` and `certChain` fields.
* `GET /vaults/{vaultId}/wallets`: Signed address responses can now include `signatureVersion` and `certChain` fields.
* `POST /vaults/{vaultId}/wallets`: Signed address responses can now include `signatureVersion` and `certChain` fields.
* `GET /wallets`: Signed address responses can now include `signatureVersion` and `certChain` fields.
* `GET /wallets/{walletId}`: Signed address responses can now include `signatureVersion` and `certChain` fields.
**Impact**: This is a backward-compatible change that gives clients a more robust, certificate-based way to verify deposit address authenticity. When `signatureVersion` is `V2`, the `certChain` field contains an x509 certificate chain for verification against a trusted Anchorage Digital Root CA; if `certChain` is absent, use the existing V1 signature verification method. See the [Address Verification guide](https://developers.anchorage.com/docs/address-verification) for instructions.
## Added MINT Transaction Type
**Added** `MINT` as a new transaction type to represent assets minted or created on the blockchain.
**Category**: Transactions
**Endpoints Changed**:
* `GET /transactions`: The `types` query parameter now accepts `MINT` to filter transactions, and the `transactionType` field in the response can now return `MINT`.
* `GET /transactions/{transactionId}`: The `transactionType` field in the response can now return `MINT`.
**Impact**: You can now filter for and identify `MINT` transactions across both the list and single-transaction endpoints.
## Improved Error Handling for Collateral Package Updates
**Improved** error handling by adding a new `422 Unprocessable Entity` error response to the update collateral package endpoint.
**Category**: Collateral Management
**Endpoint Changed**:
* `PATCH /collateral_management/packages/{packageId}`: Now returns `422 Unprocessable Entity` for requests that are syntactically correct but semantically invalid.
**Impact**: This lets clients differentiate between a bad request (`400`), a resource not found (`404`), and an unprocessable entity (`422`).
## Improved Pricing Options for Collateral Management
**Improved** Added new options for price strategy and price source to provide more flexibility in Collateral Management configurations.
**Category**: Collateral Management
**Endpoints Changed**:
* `POST /collateral_management/packages`: The `priceStrategy` field now accepts `VWAP`, and the `priceSource` field now accepts `KAMINO`.
* `PATCH /collateral_management/packages/{packageId}`: The `priceStrategy` field now accepts `VWAP`, and the `priceSource` field now accepts `KAMINO`.
* `POST /collateral_management/exposures`: The `priceStrategy` field now accepts `VWAP`, and the `priceSource` field now accepts `KAMINO`.
**Impact**: You can now specify `VWAP` (Volume-Weighted Average Price) as a pricing strategy and `KAMINO` as a price source when creating or updating collateral packages and exposures.
## Added BURN Transaction Type
**Added** a new `BURN` transaction type to represent assets that are burned or destroyed on the blockchain.
**Category**: Transactions
**Endpoints Changed**:
* `GET /transactions`: The `types` query parameter now accepts `BURN` to filter transactions, and the `transactionType` field in the response can now return `BURN`.
* `GET /transactions/{transactionId}`: The `transactionType` field in the response can now return `BURN`.
**Impact**: This helps with clearer categorization of on-chain asset destruction events.
## Removed priceSourceProvider from Collateral Management Endpoints
**Removed** the `priceSourceProvider` field from the request bodies of several Collateral Management endpoints.
**Category**: Collateral Management
**Endpoints Changed**:
* `POST /collateral_management/packages`: The `priceSourceProvider` field is no longer available in `collateralAssetsConfig`.
* `PATCH /collateral_management/packages/{packageId}`: The `priceSourceProvider` field is no longer available in `collateralAssetsConfig`.
* `POST /collateral_management/exposures`: The `priceSourceProvider` field is no longer available in `assetTrackingConfig`.
**Impact**: API requests that include the `priceSourceProvider` field will now result in an error. Update your integrations to remove this field to ensure successful requests.
## Improved Collateral Management Operations with GAS\_FEE Action
**Improved** the `CMOperation` model to include a new `GAS_FEE` action type.
**Category**: Collateral Management
**Endpoints Changed**:
* `PATCH /collateral_management/operations/{operationId}`: The `action` field in the response can now include `GAS_FEE`.
* `GET /collateral_management/operations`: The `action` field in the response can now include `GAS_FEE`.
**Impact**: This provides more granular detail on operation types.
## Improved Fiat Deposit Instructions with Memo Field
**Improved** A `memoField` has been added to the `depositInstruction` object returned for fiat wallets.
**Category**: Wallets
**Endpoints Changed**:
* `GET /vaults/{vaultId}/wallets`: The `depositInstruction` object for fiat wallets now includes `memoField`.
* `POST /vaults/{vaultId}/wallets`: The `depositInstruction` object for fiat wallets now includes `memoField`.
* `GET /wallets`: The `depositInstruction` object for fiat wallets now includes `memoField`.
* `GET /wallets/{walletId}`: The `depositInstruction` object for fiat wallets now includes `memoField`.
**Impact**: This is a non-breaking, additive change. Include this memo on wire deposits to ensure funds are attributed correctly to the wallet.
**Example**:
```json theme={null}
"depositInstruction": {
"memoField": "123456789",
"bankName": "Example Bank",
"bankRoutingNumber": "123456789",
"bankAddress": "123 Main Street, Anytown, USA 12345",
"bankSwiftCode": "12345678",
"beneficiaryName": "John Doe",
"beneficiaryAddress": "123 Main Street, Anytown, USA 12345",
"beneficiaryAccountNumber": "12345678"
}
```
## Improved Wallet Details with Fiat Deposit Instructions
**Improved** Wallet-related endpoints now include a `depositInstruction` object with banking details for fiat wallets, distinct from crypto wallet addresses.
**Category**: Wallets
**Endpoints Changed**:
* `GET /vaults/{vaultId}/wallets`: The response now conditionally includes the `depositInstruction` object for fiat wallets.
* `POST /vaults/{vaultId}/wallets`: The response now conditionally includes the `depositInstruction` object for fiat wallets.
* `GET /wallets`: The response now conditionally includes the `depositInstruction` object for fiat wallets.
* `GET /wallets/{walletId}`: The response now conditionally includes the `depositInstruction` object for fiat wallets.
**Impact**: The `depositAddress` object remains for crypto wallets. The description for the `assets` array has also been clarified to state that it may be empty.
**Example**:
```json theme={null}
"depositInstruction": {
"bankName": "Example Bank",
"bankAddress": "123 Finance St, New York, NY",
"bankRoutingNumber": "123456789",
"bankSwiftCode": "EXMPUS33",
"beneficiaryName": "Anchorage Digital Bank, N.A.",
"beneficiaryAddress": "456 Custody Ave, Sioux Falls, SD",
"beneficiaryAccountNumber": "987654321",
"memoField": "For further credit to [Your Org Name]"
}
```
## Improved Collateral Management Package Updates and API Refinements
**Improved** the Collateral Management API for more comprehensive control and clarity, including support for partial updates to a package's entire configuration.
**Category**: Collateral Management
**Endpoints Changed**:
* `PATCH /collateral_management/packages/{packageId}`: You can now update nearly all configuration details of a package, including `clientReferenceId`, `collateralAssetsConfig`, `ltvRoundingPrecision`, `priceStrategy`, and settings for `critical`, `marginCall`, `marginReturn`, and `autoDeleveraging` levels; omitted fields remain unchanged.
* `PATCH /collateral_management/operations/{operationId}`: The `type` field no longer accepts the `LIQUIDATION` enum value, and the `typeId` description was improved for clarity.
* `POST /collateral_management/operations`: The `type` field no longer accepts the `LIQUIDATION` enum value, and the `typeId` description was improved for clarity.
* `GET /collateral_management/exposures`: Field descriptions were updated for accuracy and clarity.
* `POST /collateral_management/packages`: Field descriptions were updated for accuracy and clarity.
* `GET /collateral_management/packages`: Field descriptions were updated for accuracy and clarity.
**Impact**: These changes provide significantly more flexibility for programmatically managing collateral packages and improve the overall clarity and usability of the Collateral Management API.
## Added Collateral Management Operation Actions
**Added** new `action` types for creating and updating Collateral Management operations.
**Category**: Collateral Management
**Endpoints Changed**:
* `POST /collateral_management/operations`: The `action` field now supports `CLOSE_RETURN`, `REHYPE_IN`, and `REHYPE_OUT`.
* `PATCH /collateral_management/operations/{operationId}`: The `action` field now supports `CLOSE_RETURN`, `REHYPE_IN`, and `REHYPE_OUT`.
**Impact**: You can now create and update operations to manage the closing of returns and rehypothecation for collateral packages.
## Added Fields for Tax Transaction Tagging
**Added** new conditional fields for tagging tax transactions to support more detailed reporting.
**Category**: Tax
**Endpoint Changed**:
* `POST /tax/transaction/{transactionId}/tag`: The request body now supports `distributionCode` (required when `tag` is `distribution`), `totalDistribution` (required when `tag` is `distribution`), and `postponedLateReason` (required when `tag` is `postponed` or `late-rollover`).
**Impact**: When tagging transactions with `distribution`, `postponed`, or `late-rollover`, you must now provide these additional details for more accurate tax reporting.
**Example**:
```json theme={null}
{
"accountId": "SubaccountID",
"tag": "distribution",
"taxYear": "2024",
"distributionCode": "1",
"totalDistribution": true
}
```
## Improved Collateral Management API Clarity and Field Support
**Improved** several Collateral Management endpoints for clarity and functionality, with updated field descriptions and examples throughout.
**Category**: Collateral Management
**Endpoints Changed**:
* `POST /collateral_management/packages`: Removed the `defaultGroupId` parameter from the request body.
* `GET /collateral_management/packages`: Removed `acceleratedMarginCall` from the response, and added `CURE_PERIOD_EXPIRED` and `DEFAULTED` to the `state` enum.
* `POST /collateral_management/exposures`: Descriptions improved for clarity.
* `GET /collateral_management/exposures`: Descriptions improved for clarity.
* `POST /collateral_management/operations`: Removed several unsupported enum values from the `action` field to reflect currently available actions.
* `GET /collateral_management/operations`: Descriptions improved for clarity.
* `PATCH /collateral_management/operations/{operationId}`: Removed several unsupported enum values from the `action` field to reflect currently available actions.
**Impact**: Descriptions were improved across all listed endpoints for parameters such as `clientReferenceId`, `pledgorId`, `curePeriod`, `ltv`, and `topUpType`, giving clearer guidance when configuring collateral packages, exposures, and operations.
## Improved Price Strategy Options with BID and ASK
**Improved** Added `BID` and `ASK` as valid options for the `priceStrategy` field when creating collateral packages and exposures.
**Category**: Collateral Management
**Endpoints Changed**:
* `POST /collateral_management/packages`: The `priceStrategy` field now accepts `BID` and `ASK`.
* `POST /collateral_management/exposures`: The `priceStrategy` field now accepts `BID` and `ASK`.
**Impact**: This provides more granular control over pricing strategy, letting you specify whether the bid or ask price should be used when creating new collateral packages and exposures.
## Improved Filtering for List Orders Endpoint
**Improved** order filtering capabilities by adding a new `orderTypes` parameter.
**Category**: Trading
**Endpoint Changed**:
* `GET /trading/orders`: Accepts a new optional `orderTypes` query parameter, an array of strings to filter by order type (`LIMIT`, `MARKET`, `STOP_LOSS`, `STOP_LIMIT`, `TAKE_PROFIT_LIMIT`, `TWAP`, `VWAP`, `PEGGED`, `POV`, `OTHER`).
**Impact**: This allows for more granular querying of orders, letting you retrieve only the specific order types you're interested in.
**Example**: `GET /v2/trading/orders?orderTypes=LIMIT,STOP_LIMIT`
## Improved Customer Onboarding with Single-Call Submission
**Improved** the customer onboarding workflow by adding an optional `submit` parameter.
**Category**: Onboarding
**Endpoint Changed**:
* `POST /onboarding/customers`: Accepts a new optional boolean `submit` parameter.
**Impact**: This is a non-breaking change. When `submit` is `true`, the application is created and submitted in a single call, eliminating the need for a separate submission request and reducing the number of required API calls.
## Improved Price Source Options with KRAKEN
**Improved** Added `KRAKEN` as a supported price source for collateral management.
**Category**: Collateral Management
**Endpoints Changed**:
* `POST /collateral_management/packages`: The `priceSource` field now accepts `KRAKEN`.
* `POST /collateral_management/exposures`: The `priceSource` field now accepts `KRAKEN`.
**Impact**: This provides more flexibility by letting you select Kraken as the data source for asset pricing when configuring collateral.
# Errors, rate limits, and pagination
Source: https://docs.anchorage.com/knowledge-base/api-reference/errors-pagination
Understand Anchorage API status codes, rate limits, idempotent retries, and cursor pagination.
Standard HTTP status codes with a human-readable error message when requests fail.
Know your limits when accessing the Anchorage API to avoid 429 errors.
Required on certain endpoints to avoid duplicative operations.
Paginate through pages of API results.
## Status codes
| Code | Meaning |
| ----------------------- | -------------------------------------------------------------------------------------------------------------------- |
| `200 OK` | The request was successful. |
| `400 Bad Request` | The request was improperly formed, often due to invalid syntax, insufficient funds, or a missing required parameter. |
| `401 Unauthorized` | The request was missing a valid API key. |
| `403 Forbidden` | The API key does not have permission to perform the requested action. |
| `404 Not Found` | The requested resource does not exist. |
| `409 Conflict` | The requested action cannot proceed because the resource is not in the required state. |
| `429 Too Many Requests` | Too many requests were sent in a given amount of time. |
| `5xx` | Something went wrong on Anchorage Digital's side. |
### Common money movement errors
These are the failures developers hit most often when moving assets, and how to resolve each.
| Symptom | Likely cause | Resolution |
| :------------------------------------------------------------------------------------------ | :----------------------------------------------------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `403` on an external transfer (`Cannot find role permission action for external transfers`) | The key's permission group doesn't have external transfers enabled, or a destination-scoped permission isn't connected to the destination. | Enable external transfers on the permission group. If the permission is scoped to specific destinations, connect the trusted destination to the group and endorse it. See [Permission groups and API keys](/knowledge-base/platform/developers/move-money/setup/permission-groups). |
| `403` on any movement | The key lacks the required permission for the source vault (for example `Transfer funds` or `Initiate withdrawals`). | Grant the permission to the key's group and re-endorse. |
| `400` insufficient funds | The amount plus the network fee exceeds the wallet's available balance. | Lower the amount, or on transfers set `deductFeeFromAmountIfSameType: true` to net the fee out of the amount. |
| `400` invalid or unsupported | A required field is missing, or the source wallet or destination doesn't support the asset. | Confirm the asset (`GET /v2/asset-types`) and that both source and destination support it. |
| `409` conflict on a withdrawal | A withdrawal is already in flight from the source wallet—withdrawals don't queue. | Wait for the in-flight withdrawal to broadcast or fail, then retry. |
| `429` too many requests | The org-wide rate limit was exceeded. | Back off and retry (see [Retries and backoff](#retries-and-backoff)). |
A request that returns `201` can still fail at execution—after quorum approval or at broadcast—if there are insufficient funds for the network fee or a blockchain-level failure occurs. Track terminal status via [Track movement status](/knowledge-base/platform/developers/move-money/operate/track-status).
## Rate limits
Keys provisioned by an organization share one common rate limit. API requests are
limited to `20 requests/second` per organization, allowing bursts of up to `100
requests` within a single second.
## Idempotency
Certain endpoints support idempotent requests so retries do not perform the same
operation twice. For example, if a transfer request does not respond because of a
network issue, retry with the same idempotent ID to ensure only one transfer is
created.
For supported endpoints, include a unique `idempotentId` in the `POST` request body.
```json theme={null}
{
"idempotentId": "9f8fbb54-7f5b-4993-829b-758b4c5f7e65"
}
```
## Retries and backoff
Retry `429` and `5xx` responses with exponential backoff—for example, 1s, 2s, 4s, then 8s. When retrying a `POST`, reuse the same `idempotentId` so a request that succeeded but didn't return its response doesn't execute twice. Don't retry other `4xx` responses: they indicate a request that needs to be corrected, not repeated.
## Pagination
Cursor pagination is used for endpoints that return multiple records. Responses
include a `next` cursor in the `page` attribute when more results are available.
```http theme={null}
GET /v2/transfers?afterId=1968b94b09b8a1a8a381775d1f04978c424d891d50e517774bf984297985b471&limit=100
```
| Parameter | Description |
| --------- | ------------------------------------------------------------------------------------------------------------------- |
| `afterId` | Request a page after, or older than, this pagination ID. |
| `endDate` | Request records older than this date in `YYYY-MM-DD` format. Used for `/trading/trades` and `/trading/settlements`. |
| `limit` | Maximum number of results requested. Defaults vary by resource. |
# Introduction
Source: https://docs.anchorage.com/knowledge-base/api-reference/introduction
Introduction for the Anchorage Digital REST API v2.0
The Anchorage Digital API is a REST API that consists of 100+ operations across custody,
wallets, transfers, trading, Atlas settlement, onboarding, tax, subaccounts, webhook notifications, and
more.
Building with an AI assistant? Connect the Anchorage Digital docs MCP server or start from ready-made prompts. See [Build with AI](/knowledge-base/build-with-ai/overview).
## Base URLs
| Environment | Base URL |
| :---------- | :---------------------------------- |
| Sandbox | `https://api.anchorage-staging.com` |
| Production | `https://api.anchorage.com` |
## Send your first API call
Define which vaults and operations the API key can access. See [Permission groups](/knowledge-base/platform/developers/permission-groups).
Generate a key assigned to the permission group. See [API keys](/knowledge-base/platform/developers/api-keys).
Sensitive endpoints require an Ed25519 signature in addition to the API key. See [Request signing](/knowledge-base/platform/developers/request-signing).
Include your API key in the `Api-Access-Key` header on every request. Add `Api-Signature` and `Api-Timestamp` on sensitive endpoints.
```bash theme={null}
curl -X GET \
'https://api.anchorage-staging.com/v2/apikey' \
-H 'Api-Access-Key: ' \
-H 'Api-Signature: ' \
-H 'Api-Timestamp: '
```
## Next steps
Learn how requests are signed and attached to headers.
Learn how requests are signed and attached to headers.
Handle response codes, rate limits, and cursor pagination.
# List all addresses for an asset
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/addresses/list-all-addresses-for-an-asset
/knowledge-base/openapi/v2.yaml get /vaults/{vaultId}/addresses
Permissions required: **Read vault activity** or **Create address**
Get all addresses for the asset type within the specified `vaultId`.
# Provision a deposit address for a wallet
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/addresses/provision-a-deposit-address-for-a-wallet
/knowledge-base/openapi/v2.yaml post /wallets/{walletId}/addresses
Permissions required: **Create address**
This endpoint allows you to request an asynchronous provision of a signed deposit address for a given wallet. For UTXO-based wallets a new address will always be provisioned upon request. For account-based wallets only one address may be provisioned per wallet and subsequent attempts will return the previously provisioned address.
Newly requested addresses may not be available for several minutes once requested.
# List information for current API key
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/api-key/list-information-for-current-api-key
/knowledge-base/openapi/v2.yaml get /apikey
Permissions required: none
Get the user information for your API key.
As with any endpoint, a signature included in the request will be validated. This can be used to confirm the associated signing key as well information about the current API key.
# List supported asset types
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/asset-types/list-supported-asset-types
/knowledge-base/openapi/v2.yaml get /asset-types
Permissions required: none
List all of the supported asset types for your organization. Each asset type object includes the name of the asset (ex. Bitcoin) as well as the asset type (ex. BTC), which usually corresponds to the asset's ticker symbol.
#### Filters
You may optionally supply the following filters:
- Specify the `asset types` to filter the organization asset types. Multiple asset types should be separated by commas.
For example:
To filter a single asset type to only Bitcoin we can use /v2/asset-types?assetTypes=BTC
To filter multiple asset types for instance Bitcoin and Ethereum we could use /v2/asset-types?assetTypes=BTC,ETH
- Specify the `feature types` to filter the organization asset types. Multiple features should be separated by commas.
For example:
To filter all organization assets that have the HOLD feature we can use /v2/asset-types?assetFeatures=HOLDS
To filter all organization assets that have the HOLD or TRANSFERS feature we can use /v2/asset-types?assetFeatures=HOLDS,TRANSFERS
# Accept a settlement
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/atlas-settlement-network/accept-a-settlement
/knowledge-base/openapi/v2.yaml post /atlas/settlements/{settlementId}/accept
Permissions required: **Propose and Accept settlements** and **Read vault activity**
Accept a proposed settlement and select wallets to receive funds to and/or send funds from.
# Authorize a settlement
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/atlas-settlement-network/authorize-a-settlement
/knowledge-base/openapi/v2.yaml post /atlas/settlements/{settlementId}/authorize
Permissions required: **Authorize Settlements**
After your participant has proposed a settlement or accepted a settlement proposal, the details of the settlement must be authorized.
To authorize via API, the API key must have a special permission. Otherwise, authorization takes place in the app according to organization policy.
# Get a counterparty by ID
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/atlas-settlement-network/get-a-counterparty-by-id
/knowledge-base/openapi/v2.yaml get /atlas/directory/counterparties/{counterpartyId}
Permissions required: **Read vault activity**
Get a single trusted counterparty by its ID.
# Get a participant by ID
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/atlas-settlement-network/get-a-participant-by-id
/knowledge-base/openapi/v2.yaml get /atlas/directory/participants/{participantId}
Permissions required: **Read vault activity**
Get a single participant by its ID.
# Get a settlement by ID
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/atlas-settlement-network/get-a-settlement-by-id
/knowledge-base/openapi/v2.yaml get /atlas/settlements/{settlementId}
Permissions required: **Read vault activity**
Get a single settlement by its ID.
# List participants
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/atlas-settlement-network/list-participants
/knowledge-base/openapi/v2.yaml get /atlas/directory/participants
Permissions required: **Read vault activity**
Get the list of participants you have access to.
# List settlements
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/atlas-settlement-network/list-settlements
/knowledge-base/openapi/v2.yaml get /atlas/settlements
Permissions required: **Read vault activity**
Get settlements proposed by you or proposed to you.
# List trusted counterparties
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/atlas-settlement-network/list-trusted-counterparties
/knowledge-base/openapi/v2.yaml get /atlas/directory/counterparties
Permissions required: **Read vault activity**
Get trusted counterparties.
# Propose a settlement
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/atlas-settlement-network/propose-a-settlement
/knowledge-base/openapi/v2.yaml post /atlas/settlements
Permissions required: **Propose and Accept settlements**
Propose a settlement with a counterparty for a list of assets coming from and/or arriving into wallets owned by your participant.
Positive amounts indicate funds to be received and negative amounts indicate funds to be sent.
```json
[
{
"walletId": "d4578f401daadff65615236c5ad1e12c",
"quantity": "-1.1",
"assetType": "BTC"
},
{
"walletId": "43a9aeac02c851f4868f9d89aabde494",
"quantity": "20.62",
"assetType": "ETH"
}
]
```
For example, the above wallet amounts indicate you will send 1.1 BTC from your wallet `d4578f401daadff65615236c5ad1e12c` and receive 20.62 ETH into your wallet `43a9aeac02c851f4868f9d89aabde494`.
The steps to create a settlement are:
1. The proposer participant proposes it, selecting an acceptor, assets, amounts and wallets.
2. The proposer authorizes it, either through the API or mobile app signing.
3. The acceptor participant accepts it, selecting wallets to use.
4. (optional) The acceptor authorizes it, either through the API or mobile app signing.
5. The settlement is funded in the sending wallets.
6. The assets are transferred on-chain, as directed by the settlement.
Steps 2 or 3 can happen out of order.
Step 4 is skipped if the acceptor is not sending any assets.
The settlement stays in the `ActionNeeded` state until it reaches step 6. Then it enters the `Executing` state and, after that, it enters one of the final states.
# Propose a trusted counterparty
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/atlas-settlement-network/propose-a-trusted-counterparty
/knowledge-base/openapi/v2.yaml post /atlas/directory/counterparties
Permissions required: **Propose Trusted Counterparty**
Propose adding a new trusted counterparty for a participant.
# Reject a settlement proposal
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/atlas-settlement-network/reject-a-settlement-proposal
/knowledge-base/openapi/v2.yaml post /atlas/settlements/{settlementId}/reject
Permissions required: **Propose and Accept settlements** or **Authorize Settlements**
Rejects a proposed settlement for your Atlas participant. Proposed settlements cannot be rejected if they have already been authorized.
# Request a collateral decrease
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/collateral-decrease
POST /collateral_management/packages/{packageId}/collateral-decrease
Request a collateral decrease for a package.
# Create a new collateral package
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/collateral-management/create-a-new-collateral-package
/knowledge-base/openapi/v2.yaml post /collateral_management/packages
Permissions required: **Manage Collateral Packages** and **Read vault activity**
Creates a new collateral package in the Collateral Management service.
# Create a new exposure
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/collateral-management/create-a-new-exposure
/knowledge-base/openapi/v2.yaml post /collateral_management/exposures
Permissions required: **Manage Collateral Exposures** and **Read vault activity**
Creates a new exposure in the Collateral Management service.
# Create a new operation
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/collateral-management/create-a-new-operation
/knowledge-base/openapi/v2.yaml post /collateral_management/operations
Permissions required: **Manage Collateral Packages** and **Read vault activity**
Create a new operation in the Collateral Management service.
# List collateral and exposure operations
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/collateral-management/list-collateral-and-exposure-operations
/knowledge-base/openapi/v2.yaml get /collateral_management/operations
Permissions required: **Read vault activity**
Get all the operations that were booked for collateral packages and exposures.
# List exposures
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/collateral-management/list-exposures
/knowledge-base/openapi/v2.yaml get /collateral_management/exposures
Permissions required: **Read vault activity**
Get Exposures.
# List packages
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/collateral-management/list-packages
/knowledge-base/openapi/v2.yaml get /collateral_management/packages
Permissions required: **Read vault activity**
Get collateral packages.
# Update a collateral package
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/collateral-management/update-a-collateral-package
/knowledge-base/openapi/v2.yaml patch /collateral_management/packages/{packageId}
Permissions required: **Manage Collateral Packages** and **Read vault activity**
Updates an existing collateral package in the Collateral Management service.
# Update an operation
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/collateral-management/update-an-operation
/knowledge-base/openapi/v2.yaml patch /collateral_management/operations/{operationId}
Permissions required: **Manage Collateral Packages** and **Read vault activity**
Update an existing operation in the Collateral Management service.
Only the fields provided in the request body will be updated.
# Get collateral price sources
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/collateral-price-sources
GET /collateral_management/price_sources
Get available assets for specific price sources.
# Attribute a deposit
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/deposit-attribution/attribute-a-deposit
/knowledge-base/openapi/v2.yaml patch /deposit-attributions/{depositTransactionId}
Permissions required: **Deposit Attribution**.
Attribute a deposit by providing information about the originator.
Only attributions in `PENDING` status can be attributed.
Once the attribution is successfully performed the attribution status moves from `PENDING` to `UNDER_REVIEW`.
For attributions performed via API the attributionType will always be `CLIENT_API`.
# Attribute a deposit as spam
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/deposit-attribution/attribute-a-deposit-as-spam
/knowledge-base/openapi/v2.yaml post /deposit-attributions/{depositTransactionId}/spam
Permissions required: **Deposit Attribution**.
Attribute a deposit as spam.
Only attributions in `PENDING` status can be attributed.
Once the attribution is successfully performed the attribution status moves from `PENDING` to `ATTRIBUTED`.
For any spam attribution performed via API, the attributionType will automatically be set to `SPAM` and the deposit's funds will cease to be available.
# List deposit attributions
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/deposit-attribution/list-deposit-attributions
/knowledge-base/openapi/v2.yaml get /deposit-attributions/attributions
Permissions required: **Read Deposit Attribution** or **Deposit Attribution**.
Returns all Deposit Attributions for an Organization based on the provided query parameters.
Default sorting will be ascending order by createdAt.
# Off-chain vesting schedules
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/offchainvesting-schedules
GET /offchainvesting/schedules
Retrieve off-chain vesting schedules.
# Begin new customer onboarding application
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/onboarding/begin-new-customer-onboarding-application
/knowledge-base/openapi/v2.yaml post /onboarding/customers
Permissions required: **Onboarding**
Initiate onboarding application for a new customer of Anchorage Digital
# Begin new customer subaccount onboarding application
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/onboarding/begin-new-customer-subaccount-onboarding-application
/knowledge-base/openapi/v2.yaml post /onboarding/subaccounts
Permissions required: **Onboarding**
Initiate onboarding application for a new customer subaccount of Anchorage Digital
# Creates a new agreement questionnaire of the given agreementType
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/onboarding/creates-a-new-agreement-questionnaire-of-the-given-agreementtype
/knowledge-base/openapi/v2.yaml post /onboarding/agreements/{agreementType}
Permissions required: **Onboarding**
Creates a new agreement questionnaire
# Request a signed URL for document image upload
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/onboarding/request-a-signed-url-for-document-image-upload
/knowledge-base/openapi/v2.yaml post /onboarding/customers/{customerId}/document
Permissions required: **Onboarding**
Request a signed URL for uploading document images for the existing customer onboarding application
Note that the URL expires after 15m, you can still generate a new URL if this one expires. If the image file is never uploaded, the document will show as missing in the `GET` response and a new signed URL must be requested.
# Retrieve uploaded data and status of all customers onboarding
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/onboarding/retrieve-uploaded-data-and-status-of-all-customers-onboarding
/knowledge-base/openapi/v2.yaml get /onboarding/customers
Permissions required: **Onboarding**
List all customers onboarding application status, missing information and previously uploaded information.
# Retrieve uploaded data and status of all onboarding customer subaccounts
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/onboarding/retrieve-uploaded-data-and-status-of-all-onboarding-customer-subaccounts
/knowledge-base/openapi/v2.yaml get /onboarding/subaccounts
Permissions required: **Onboarding**
List all customer subaccounts onboarding application status, missing information and previously uploaded information.
# Retrieve uploaded data and status of customer onboarding
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/onboarding/retrieve-uploaded-data-and-status-of-customer-onboarding
/knowledge-base/openapi/v2.yaml get /onboarding/customers/{customerId}
Permissions required: **Onboarding**
Get customer onboarding application status, missing information and previously uploaded information.
# Retrieve uploaded data and status of customer subaccount onboarding
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/onboarding/retrieve-uploaded-data-and-status-of-customer-subaccount-onboarding
/knowledge-base/openapi/v2.yaml get /onboarding/subaccounts/{subaccountId}
Permissions required: **Onboarding**
Get customer subaccount onboarding application status, missing information and previously uploaded information.
# Retrieves all the agreements questionnaires for the specified agreement type
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/onboarding/retrieves-all-the-agreements-questionnaires-for-the-specified-agreement-type
/knowledge-base/openapi/v2.yaml get /onboarding/agreements/{agreementType}
Permissions required: **Onboarding**
Retrieves all the agreements questionnaires for the specified agreement type
# Retrieves the agreement questionnaire of the given agreement type and agreement ID
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/onboarding/retrieves-the-agreement-questionnaire-of-the-given-agreement-type-and-agreement-id
/knowledge-base/openapi/v2.yaml get /onboarding/agreements/{agreementType}/{agreementId}
Permissions required: **Onboarding**
Retrieves the agreement questionnaire for the specified agreement type and agreement ID
# Submit a completed customer onboarding application
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/onboarding/submit-a-completed-customer-onboarding-application
/knowledge-base/openapi/v2.yaml post /onboarding/customers/{customerId}/submit
Permissions required: **Onboarding**
Indicate that a customer onboarding application is complete and can be submitted for screening
# Submit a completed customer subaccount onboarding application
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/onboarding/submit-a-completed-customer-subaccount-onboarding-application
/knowledge-base/openapi/v2.yaml post /onboarding/subaccounts/{subaccountId}/submit
Permissions required: **Onboarding**
Indicate that a customer subaccount onboarding application is complete and can be submitted for screening
# Update customer onboarding application
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/onboarding/update-customer-onboarding-application
/knowledge-base/openapi/v2.yaml put /onboarding/customers/{customerId}
Permissions required: **Onboarding**
Update an existing customer onboarding application. The application data will be updated to match the entries of the update payload. If any field is invalid, the entire update will fail and no data will be updated.
# Update customer subaccount onboarding application
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/onboarding/update-customer-subaccount-onboarding-application
/knowledge-base/openapi/v2.yaml put /onboarding/subaccounts/{subaccountId}
Permissions required: **Onboarding**
Update data of an existing customer subaccount onboarding application
# Create a Stablecoin Conversion
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/stablecoins/create-a-stablecoin-conversion
/knowledge-base/openapi/v2.yaml post /stablecoins/conversion
Permissions required: **Convert Stablecoins**
Create a stablecoin conversion, either issuance or redemption. Issuance is when USD is converted to the stablecoin. Redemption is when the stablecoin asset is converted to USD.
# Get Issue/Redeem History
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/stablecoins/get-issueredeem-history
/knowledge-base/openapi/v2.yaml get /stablecoins/history
Permissions required: **Convert Stablecoins**
Retrieve the history of stablecoin issuance and redemption operations for your organization.
Results are paginated and ordered by creation time (newest first).
# Get Stablecoin Reserves Entitled Stablecoins
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/stablecoins/get-stablecoin-reserves-entitled-stablecoins
/knowledge-base/openapi/v2.yaml get /stablecoins/reserves/entitled-stablecoins
Permissions required: **Read vault activity**
List the stablecoins whose reserves history your organization is entitled to view. Pass any returned symbol as the `stablecoin` query parameter to `GET /stablecoins/reserves` to retrieve that stablecoin's daily reserves reconciliation history. Returns an empty array when your organization cannot view reserves history for any stablecoin.
# Get Stablecoin Reserves History
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/stablecoins/get-stablecoin-reserves-history
/knowledge-base/openapi/v2.yaml get /stablecoins/reserves
Permissions required: **Read vault activity**
Retrieve the daily reserves reconciliation history for a stablecoin your organization is entitled to.
Results are paginated and ordered by creation time (newest first).
# Download a statement
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/statement-download
GET /statements/{statementId}/download
Download a statement.
# Get statement
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/statement-get
GET /statements/{statementId}
Get a statement.
# List statement types
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/statement-types
GET /statement-types
List statement types.
# List statements
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/statements-list
GET /statements
List statements.
# Cancel Manual Billing Charge
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/subaccounts/cancel-manual-billing-charge
/knowledge-base/openapi/v2.yaml delete /subaccounts/billing/charges/{chargeId}
Permissions required: **Subaccount**
Cancel Manual Billing Charge
# Cancels a Withdrawal Request for a subaccount
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/subaccounts/cancels-a-withdrawal-request-for-a-subaccount
/knowledge-base/openapi/v2.yaml delete /subaccounts/{subaccountId}/fiat/withdrawals/{transactionId}
Permissions required: **Subaccount**
Cancels a Withdrawal Request
# Create a new subaccount for a given program customer
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/subaccounts/create-a-new-subaccount-for-a-given-program-customer
/knowledge-base/openapi/v2.yaml post /subaccounts/customers/{customerId}/accounts
Permissions required: **Subaccount**
Open a new subaccount for the program customer
DEPRECATED, please use /onboarding/accounts
# Create a USD Withdrawal Request for a subaccount
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/subaccounts/create-a-usd-withdrawal-request-for-a-subaccount
/knowledge-base/openapi/v2.yaml post /subaccounts/{subaccountId}/fiat/withdrawals
Permissions required: **Subaccount**
Creates a USD Withdrawal Request for an Asset within a Subaccount (FIAT only for now)
This will trigger an e-mail to be sent to the program customer to authorize the withdrawal.
# Create Manual Billing Charge
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/subaccounts/create-manual-billing-charge
/knowledge-base/openapi/v2.yaml post /subaccounts/billing/charges
Permissions required: **Subaccount**
Create Manual Billing Charge
# Create new allocations
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/subaccounts/create-new-allocations
/knowledge-base/openapi/v2.yaml post /subaccounts/transactions/allocations
Permissions required: **Subaccount**
Create new allocation of pre-funded values between the Funding and Program Customers' subaccounts. This is a transactional operation, all transactions will be created successfully or none will.
# Create new transactions
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/subaccounts/create-new-transactions
/knowledge-base/openapi/v2.yaml post /subaccounts/transactions
Permissions required: **Subaccount**
Create new transactions between subaccounts of the same Program Customer. This is a transactional operation, all transactions will be created successfully or none will.
# Fetches a set of filtered transactions allocations
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/subaccounts/fetches-a-set-of-filtered-transactions-allocations
/knowledge-base/openapi/v2.yaml get /subaccounts/transactions/allocations
Permissions required: **Subaccount** or **Read Subaccount**
Retrieves a filtered set of transactions that are connected to funding allocations.
# Fetches a set of Withdrawals Requests for a subaccount
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/subaccounts/fetches-a-set-of-withdrawals-requests-for-a-subaccount
/knowledge-base/openapi/v2.yaml get /subaccounts/{subaccountId}/fiat/withdrawals
Permissions required: **Subaccount** or **Read Subaccount**
Retrieves a filtered set of Withdrawal Requests within a Subaccount (FIAT only for now).
# Get list of transactions filter by ID
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/subaccounts/get-list-of-transactions-filter-by-id
/knowledge-base/openapi/v2.yaml get /subaccounts/transactions/{transactionsIds}
Permissions required: **Subaccount** or **Read Subaccount**
Return the requested transactions, sorted by the creation date, the client has access too
# Get USD Withdrawal Request for a subaccount
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/subaccounts/get-usd-withdrawal-request-for-a-subaccount
/knowledge-base/openapi/v2.yaml get /subaccounts/{subaccountId}/fiat/withdrawals/{transactionId}
Permissions required: **Subaccount**
Get a USD Withdrawal Request
# List all subaccounts
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/subaccounts/list-all-subaccounts
/knowledge-base/openapi/v2.yaml get /subaccounts/customers/accounts
Permissions required: **Subaccount** or **Read Subaccount**
Return all subaccounts associated for an organization
# List all transactions
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/subaccounts/list-all-transactions
/knowledge-base/openapi/v2.yaml get /subaccounts/transactions
Permissions required: **Subaccount** or **Read Subaccount**
Return all the transactions, sorted by the creation date, the client has access to
# List subaccounts
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/subaccounts/list-subaccounts
/knowledge-base/openapi/v2.yaml get /subaccounts/customers/{customerId}/accounts
Permissions required: **Subaccount** or **Read Subaccount**
Return all subaccounts associated to a customerId
# Return bank information for a subaccount
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/subaccounts/return-bank-information-for-a-subaccount
/knowledge-base/openapi/v2.yaml get /subaccounts/accounts/{subaccountId}/bank-info
Permissions required: **Subaccount** or **Read Subaccount**
Return bank information for a subaccount
# Return wallets linked to a subaccount
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/subaccounts/return-wallets-linked-to-a-subaccount
/knowledge-base/openapi/v2.yaml get /subaccounts/accounts/{subaccountId}/wallets
Permissions required: **Subaccount** or **Read Subaccount**
Return wallets linked to a subaccount
# Update an existing subaccount
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/subaccounts/update-an-existing-subaccount
/knowledge-base/openapi/v2.yaml patch /subaccounts/accounts/{subaccountId}
Permissions required: **Subaccount**
Update a subaccount
# Apply tags to an entity
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/tagging/apply-tags-to-an-entity
/knowledge-base/openapi/v2.yaml post /tags/apply
Apply a set of tags to an entity, replacing the entity's existing tags of the given tag type. Tags are auto-created if they do not exist, and an empty list clears the entity's tags of that type.
# List tags
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/tagging/list-tags
/knowledge-base/openapi/v2.yaml get /tags
List tags filtered by ownership type and/or entity. When entityId is provided, returns tags applied to that entity. When type is provided, filters tag definitions by ownership type.
# Remove a tag from an entity
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/tagging/remove-a-tag-from-an-entity
/knowledge-base/openapi/v2.yaml delete /tags/apply/{entityId}/{tagName}
Remove a specific tag from an entity. Tag name matching is case-insensitive.
# Search entities by tag
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/tagging/search-entities-by-tag
/knowledge-base/openapi/v2.yaml get /tags/search
Search for entities that have specific tags applied. Supports cursor-based pagination.
# List deposit transactions for account
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/tax-account-transactions
GET /tax/accounts/{accountId}/transactions
List deposit transactions for a tax account.
# List tax accounts
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/tax-accounts
GET /tax/accounts
List tax accounts.
# Update deposit transaction cost basis
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/tax-transaction-cost-basis
PATCH /tax/accounts/{accountId}/transactions/{transactionId}
Update the cost basis of a deposit transaction.
# Add Tag to Transaction
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/tax/add-tag-to-transaction
/knowledge-base/openapi/v2.yaml post /tax/transaction/{transactionId}/tag
Permissions required: **Subaccount**
Tag a prior transaction for tax purposes.
** Under development **
# Get Program Customer Tax Forms
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/tax/get-program-customer-tax-forms
/knowledge-base/openapi/v2.yaml get /tax/clients/{customerId}/forms
Permissions required: **Subaccount**
Get a program customer's generated tax forms
# Get Subaccount Tax Forms
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/tax/get-subaccount-tax-forms
/knowledge-base/openapi/v2.yaml get /tax/subaccounts/{subaccountId}/forms
Permissions required: **Subaccount**
Get subaccount's generated tax forms
# List Gains
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/tax/list-gains
/knowledge-base/openapi/v2.yaml get /tax/gains/summary/{subaccountId}
Permissions required: **Subaccount**
List subaccount's gains for a period breakdown to short term, long term and total
# List Gains Cost Basis
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/tax/list-gains-cost-basis
/knowledge-base/openapi/v2.yaml get /tax/gains/costbasis/{subaccountId}
Permissions required: **Subaccount**
List subaccount's breakdown of combined cost basis, proceeds and gains/losses
# List of the Inventory for an asset
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/tax/list-of-the-inventory-for-an-asset
/knowledge-base/openapi/v2.yaml get /tax/inventory/{subaccountId}/{assetTypeId}
Permissions required: **Subaccount**
List user's inventory for an asset.
# List summary of Inventory
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/tax/list-summary-of-inventory
/knowledge-base/openapi/v2.yaml get /tax/inventory/summary/{subaccountId}
Permissions required: **Subaccount**
List user's inventory summary for all assets.
# List Transactions
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/tax/list-transactions
/knowledge-base/openapi/v2.yaml get /tax/transactions/{subaccountId}
Permissions required: **Subaccount**
List tax transactions of a subaccount.
# Remove Tag from Transaction
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/tax/remove-tag-from-transaction
/knowledge-base/openapi/v2.yaml delete /tax/transaction/{transactionId}/tag
Permissions required: **Subaccount**
Remove tax tag for a prior transaction.
** Under development **
# Update Transaction Cost Basis
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/tax/update-transaction-cost-basis
/knowledge-base/openapi/v2.yaml patch /tax/transaction/{transactionId}
Permissions required: **Subaccount**
Update the cost basis for a deposit or withdraw transaction.
# Accept a quote
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/trading/accept-a-quote
/knowledge-base/openapi/v2.yaml post /trading/quote/accept
Permissions required: **Execute trades**
Accept a quote by its quoteID and side.
#### Idempotent Requests
This endpoint supports [idempotent requests](#section/Idempotency) so that a quote cannot be accepted twice if an API call was interrupted and is retried. To send an idempotent request, include the `idempotentId` field in the body of the POST request.
# Cancel an async order
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/trading/cancel-an-async-order
/knowledge-base/openapi/v2.yaml post /trading/async-order/cancel
Permissions required: **Execute trades**
Cancels an async order.
# Get a trading account by id
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/trading/get-a-trading-account-by-id
/knowledge-base/openapi/v2.yaml get /trading/accounts/{accountId}
Permissions required: **Read trade activity**
Get trading account details by ID.
# Get market data snapshot
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/trading/get-market-data-snapshot
/knowledge-base/openapi/v2.yaml get /trading/marketdata
Permissions required: **Execute trades** or **Read trade activity**
Get real-time market data snapshot for a trading symbol from the liquidity provider.
# Get order by ID
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/trading/get-order-by-id
/knowledge-base/openapi/v2.yaml get /trading/orders/{orderId}
Permissions required: **Read trade activity** or **Execute trades** (if order created by this API key)
Get order by ID, where the ID can be anchorage generated orderId or clientOrderId
# Get settlement by ID
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/trading/get-settlement-by-id
/knowledge-base/openapi/v2.yaml get /trading/settlements/{settlementId}
Permissions required: **Execute trades** or **Read trade activity**
Get settlement details by ID.
# Get trade by ID
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/trading/get-trade-by-id
/knowledge-base/openapi/v2.yaml get /trading/trades/{tradeId}
Permissions required: **Read trade activity** or **Execute trades** (if trade created by this API key)
Get trade by ID.
# Get trading account credit limit and usage
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/trading/get-trading-account-credit-limit-and-usage
/knowledge-base/openapi/v2.yaml get /trading/accounts/{accountId}/credit
Permissions required: **Read trade activity**
Get the credit limit and usage of a trading account per asset.
Current USD prices are not returned, only assets and their quantity.
Still under development, return empty replies.
# List orders
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/trading/list-orders
/knowledge-base/openapi/v2.yaml get /trading/orders
Permissions required: **Execute trades** or **Read trade activity**
List all orders. With the permission **Read trade activity** all orders of the organization may be read. With the permission **Execute trades** only the orders created by this API key may be read.
Orders are sorted in a descending order by their timestamp, i.e. the most recent order or the order with a timestamp closest to `endDate` is listed first.
When filtering by `subaccountId`, the allocation information is included but filtered to show only the allocation for the requested subaccount.
For multi-order requests without a subaccount filter, allocation information is not included.
To get complete allocation information, use [GET `/v2/trading/orders/{orderId}`](#tag/Trading/operation/getOrderStatus)
#### Filters
You may optionally supply filters for the list of orders using query parameters below
# List outstanding trading positions
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/trading/list-outstanding-trading-positions
/knowledge-base/openapi/v2.yaml get /trading/positions
Permissions required: **Execute trades** or **Read trade activity**
Get the list of outstanding trading positions.
# List settlements
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/trading/list-settlements
/knowledge-base/openapi/v2.yaml get /trading/settlements
Permissions required: **Execute trades** or **Read trade activity**
List of all settlements. With permission **Read trade activity** all settlements of the organization may be read. With permission **Execute trades** only settlements this api key has created may be read.
Settlements are sorted in a descending order by their timestamp, i.e. the most recent settlement or the settlement with a timestamp closest to `endDate` is listed first.
#### Filters
You may optionally supply the following filters:
- Specify a one or multiple `status` to filter settlements. Multiple statuses should be separated by commas.
# List supported trading pairs
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/trading/list-supported-trading-pairs
/knowledge-base/openapi/v2.yaml get /trading/pairs
Permissions required: **Execute trades** or **Read trade activity**
List all of the supported trading pairs for your organization.
Each trading pair object includes a description and trading
symbol (ex. BTC-USD), which usually corresponds to two asset ticker symbols.
Optionally, a trading pair object includes a reference data object that details the trading precision context: minimum size increment and price increment.
# List trades
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/trading/list-trades
/knowledge-base/openapi/v2.yaml get /trading/trades
Permissions required: **Execute trades** or **Read trade activity**
List all trades. With the permission **Read trade activity** all trades of the organization may be read. With the permission **Execute trades** only the trades created by this API key may be read.
Trades are sorted in a descending order by their timestamp, i.e. the most recent trade or the trade with a timestamp closest to `endDate` is listed first.
#### Filters
You may optionally supply the following filters:
- Specify a `tradingPair` to filter by the trading pair of the trade, for example `BTC-USD`.
- Specify one or multiple `status` to filter trades. Multiple statuses should be separated by commas.
- Specify a `side` to filter by the side of the trade.
# List trades by settlement
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/trading/list-trades-by-settlement
/knowledge-base/openapi/v2.yaml get /trading/settlements/{settlementId}/trades
Permissions required: **Execute trades** or **Read trade activity**
List trades for the provided settlement. With the permission **Read trade activity** all trades of the organization may be read. With the permission **Execute trades** only the trades created by this API key may be read.
Trades are sorted in a descending order by their timestamp (i.e. the most recent trade or the trade with a timestamp closest to `endDateTime` is listed first).
# List trading account balances
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/trading/list-trading-account-balances
/knowledge-base/openapi/v2.yaml get /trading/accounts/{accountId}/balances
Permissions required: **Read trade activity**
Get the trading account balances of fiat and digital assets
# List trading accounts
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/trading/list-trading-accounts
/knowledge-base/openapi/v2.yaml get /trading/accounts
Permissions required: **Read trade activity**
Get the list of trading accounts
# Place an async order
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/trading/place-an-async-order
/knowledge-base/openapi/v2.yaml post /trading/async-order
Permissions required: **Execute trades**
Place an order, either Limit, StopLoss, StopLimit or TakeProfitLimit currently FillOrKill, ImediateOrCancel or GoodTillCancel are supported.
One of `accountId` or `subaccountId` must be specified but not both.
# Place an order
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/trading/place-an-order
/knowledge-base/openapi/v2.yaml post /trading/order
Permissions required: **Execute trades**
Place an order, either Market or Limit, currently only FillOrKill is supported.
One of `accountId` or `subaccountId` must be specified but not both.
# Request a quote
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/trading/request-a-quote
/knowledge-base/openapi/v2.yaml post /trading/quote
Permissions required: **Execute trades**
Request a quote
#### Idempotent Requests
This endpoint supports [idempotent requests](#section/Idempotency) so that quote is not requested twice if an API call was interrupted and must be retried. To send an idempotent request, include the `idempotentId` field in the body of the POST request.
# Create a collect request
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/transactions/create-a-collect-request
/knowledge-base/openapi/v2.yaml post /transactions/collect
Permissions required: **Initiate Staking and Unstaking**
In staking, the "collect" operation is the action of claiming inactive unstaked amount back to
the available balance by moving them from the staking protocol or pool into a personal wallet. Once collected, these amounts are fully under wallet's owner control.
*NOTE: This endpoint is under development.*
# Create a consolidate stake request
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/transactions/create-a-consolidate-stake-request
/knowledge-base/openapi/v2.yaml post /transactions/consolidate-stake
Permissions required: **Initiate Staking and Unstaking**
Consolidate a source staking position into a target staking position.
Only supported for Ethereum 0x02 validators.
# Create a stake request
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/transactions/create-a-stake-request
/knowledge-base/openapi/v2.yaml post /transactions/stake
Permissions required: **Initiate Staking and Unstaking**
#### Identify the sending asset
To initiate a staking operation, you must identify which asset you'd like to stake funds from. Provide a `source` and `assetType`.
#### Permissions
The provided API key must be associated with a [permission group](#section/Authentication-and-Security/Permission-Groups) that has Initiate Staking and Unstaking permission for the sending vault.
#### Additional Metadata
You may provide a `description` with each staking operation, that will be visible within your organization in the Anchorage Digital iOS Application.
#### Successful Staking
If the stake request is valid, the request will initiate a stake transaction from the sending wallet. It will still require a quorum of approvals on the Anchorage Digital iOS app and will undergo manual Anchorage Digital Risk Review. Like other transactions, these will be visible on the Anchorage Digital iOS Application, the Web Dashboard, and in the [list transactions](#operation/getTransactions) API endpoint.
#### Unsuccessful Stakes
A stake request may fail for any of the following reasons:
- An ongoing stake already exists
- The specified asset does not exist
- The specified amount exceeds the available funds for this asset (insufficient funds)
- The provided API key does not have permissions to initiate staking from this vault
If the initiated stake is approved by the quorum, the transaction may fail for any of the following reasons:
- There are insufficient funds to pay the blockchain network fee at the time of this transaction
- There is a failure on the blockchain
#### Feature under development
Currently, specific assets parameters are under development and will not be considered in any staking request. These include:
- Solana staking;
- ETH Pectra staking.
# Create a withdrawal request
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/transactions/create-a-withdrawal-request
/knowledge-base/openapi/v2.yaml post /transactions/withdrawal
Permissions required: **Initiate withdrawals**
#### Identify the sending asset
To initiate a withdrawal from a wallet to an external destination, you must identify which asset you'd like to withdraw funds from. Provide a `source` (with `id` and `type`).
#### Identify the receiving resource
Choose a resource to receive the funds as the `destination`. This resource may belong to your organization (wallet) or another organization (address, standing instruction).
#### Permissions
The provided API key must be associated with a [permission group](#section/Authentication-and-Security/Permission-Groups) that has Initiate withdrawals permission for the sending vault.
#### Additional Metadata
You may provide a `description` with each withdrawal, that will be visible within your organization in the Anchorage Digital iOS Application.
#### Successful Withdrawals
If the withdrawal request is valid, the request will initiate a withdrawal transaction from the sending wallet. This is a common withdrawal that, unlike Transfers, will still require a quorum of approvals on the Anchorage Digital iOS app and will undergo manual Anchorage Digital Risk Review. Like other transactions, these withdrawals will be visible on the Anchorage Digital iOS Application, the Web Dashboard, and in the [list transactions](#operation/getTransactions) API endpoint.
#### Unsuccessful Withdrawals
A withdrawal request may fail for any of the following reasons:
- An ongoing withdrawal already exists (unlike transfers, withdrawal requests are not queued)
- The specified asset does not exist
- The specified amount exceeds the available funds for this asset (insufficient funds)
- The destination address is invalid
- The provided API key does not have permissions to initiate withdrawals from this wallet
If the initiated withdrawal is approved by the quorum, the transaction may fail for any of the following reasons:
- There are insufficient funds to pay the blockchain network fee at the time of this transaction
- There is a failure on the blockchain
# Create an unstake request
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/transactions/create-an-unstake-request
/knowledge-base/openapi/v2.yaml post /transactions/unstake
Permissions required: **Initiate Staking and Unstaking**
#### Identify the sending asset
To initiate an unstake transaction, you must identify which asset you'd like to unstake funds from. Provide a `source` and `assetType`.
#### Permissions
The provided API key must be associated with a [permission group](#section/Authentication-and-Security/Permission-Groups) that has Initiate Staking and Unstaking permission for the sending vault.
#### Additional Metadata
You may provide a `description` with each stake, that will be visible within your organization in the Anchorage Digital iOS Application.
#### Successful Unstakes
If the stake request is valid, the request will initiate a stake transaction from the sending wallet. It will still require a quorum of approvals on the Anchorage Digital iOS app and will undergo manual Anchorage Digital Risk Review. Like other transactions, these will be visible on the Anchorage Digital iOS Application, the Web Dashboard, and in the [list transactions](#operation/getTransactions) API endpoint.
#### Unsuccessful Unstakes
A unstake request may fail for any of the following reasons:
- An ongoing unstake already exists
- The specified asset does not exist
- The specified amount exceeds the available funds to unstake for this asset (insufficient funds)
- The provided API key does not have permissions to initiate staking from this vault
If the initiated stake is approved by the quorum, the transaction may fail for any of the following reasons:
- There are insufficient funds to pay the blockchain network fee at the time of this transaction
- There is a failure on the blockchain
# Get transaction by ID
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/transactions/get-transaction-by-id
/knowledge-base/openapi/v2.yaml get /transactions/{transactionId}
Permissions required: **Read vault activity**
Get transaction by ID.
# List supported delegation addresses
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/transactions/list-supported-delegation-addresses
/knowledge-base/openapi/v2.yaml get /delegation-addresses/{assetType}
Permissions required: **Initiate Staking and Unstaking**
#### Identify the sending asset
To initiate an operation, you must identify which asset you'd like to view the delegation addresses for. Provide an `assetType`.
#### Permissions
The provided API key must be associated with a [permission group](#section/Authentication-and-Security/Permission-Groups) that has Initiate Staking and Unstaking permission for the sending vault.
# List transactions
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/transactions/list-transactions
/knowledge-base/openapi/v2.yaml get /transactions
Permissions required: **Read vault activity**
List all transactions for the vaults permissioned to your API key. You can retrieve metadata about your API key from the [API Key](#tags/API-Key) endpoints.
NOTE: price and USD value information is recent but does not reflect real-time data.
**Filters**
You may optionally supply the following filters:
- Set a date range by providing the `startDate` and/or `endDate` query parameters. The date refers to the end time of a transaction: when the transaction succeeded or failed. If the date parameters are omitted, all transactions will be returned.
- Select transactions involving a specific vault by providing the `vaultId` parameter. If the `vaultId` parameter is omitted, transactions for all vaults for which your API key is permissioned will be returned.
- Filter transactions of one or more types with the `types` parameter. Multiple types should be separated by commas.
- Select transactions involving a specific wallet by providing the `walletId` parameter. If the `walletId` parameter is omitted, transactions for all vaults for which your API key is permissioned will be returned.
- Filter transactions by the receiving address with the `destinationAddress` parameter.
# Reject a transaction
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/transactions/reject-a-transaction
/knowledge-base/openapi/v2.yaml post /transactions/{transactionId}/reject
Permissions required: **Reject Operations**
Reject an in-progress transaction. The caller's API key must hold the
`Reject Operations` permission for the source vault. Operations already
in a final state return 409 Conflict.
Only withdrawals, transfers, delegations, and generic operations
(including bridge transactions) can be rejected via this endpoint;
rejecting any other operation type returns 409 Conflict.
A transaction can only be rejected before it has been submitted for
signing and broadcast to the network. This endpoint cannot be used to
cancel a transaction stuck in the broadcasting state due to a low gas
fee.
# Cancel a transfer request
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/transfers/cancel-a-transfer-request
/knowledge-base/openapi/v2.yaml delete /transfers/{transferId}
Permissions required: **Transfer funds**
Cancel a transfer request. Transfer requests in the `QUEUED` state can always be cancelled. Transfer requests in the `IN_PROGRESS` state can sometimes be cancelled if the request has not been broadcast on the blockchain. Trying to cancel a request that cannot be cancelled will return a `409 Conflict` error code. Transfers can only be canceled by the API key responsible for creating that transfer (either created directly via CreateTransfer or indirectly via ExecuteHold)
# Create a transfer request
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/transfers/create-a-transfer-request
/knowledge-base/openapi/v2.yaml post /transfers
Permissions required: **Transfer funds**
#### Identify the sending resource and asset
To initiate a transfer between resources, you must identify which resource you'd like to transfer funds from and the asset type to transfer. Provide a `source` and `assetType`.
#### Identify the receiving resource
Choose a resource to receive the funds as the `destination`. This resource may belong to your organization or another organization that also custodies with Anchorage Digital, or it may also be an approved blockchain address not custodied by Anchorage Digital (see [Permission Groups](#section/Authentication-and-Security/Permission-Groups) for more details). Please note: If you would like to use the Anchorage Digital API to transfer to approved blockchain addresses, please contact [api@anchorage.com](mailto:api@anchorage.com).
#### Permissions
The provided API key must be associated with a permission group that has Transfer permissions for the vault from which the assets are being sent. The receiving resource does not need Transfer permissions to receive a transfer of funds.
#### Additional Metadata
You may provide a transfer memo with each transfer. If the transfer API request is successful, a transfer transaction will be created that will include this transfer memo in the description. The resulting deposit will also include this memo.
#### Successful Transfers
If the transfer request is valid, the request will initiate a transfer transaction from the source. This is a special withdrawal that will not require a quorum of approvals and will undergo automated Anchorage Digital Risk Review. When the transaction is broadcasted and confirmed on the blockchain, a subsequent deposit will be detected for the destination. All of these transactions will be visible on the Anchorage Digital iOS Application, the Web Dashboard, and in the [list transactions](#operation/getTransactions) API endpoint.
#### Unsuccessful Transfers
A transfer request may fail for any of the following reasons:
- The specified sending resource does not exist or does not support the specified asset type
- The specified amount exceeds the available funds for this asset (insufficient funds)
- The destination does not exist or does not support the specified asset type
- The provided API key does not have permissions to initiate transfers from this wallet
If the transfer request is successful, the actual transfer transaction may fail for any of the following reasons:
- There are insufficient funds to pay the blockchain network fee at the time of this transaction
- The transfer was successfully queued but there were insufficient funds by the time it was processed
- There is a failure on the blockchain
#### Idempotent Requests
This endpoint supports [idempotent requests](#section/Idempotency) so that a transfer does not occur twice if an API call was interrupted and must be retried. To send an idempotent request, include the `idempotentId` field in the body of the POST request.
#### Queueing
Transfer requests are queued and processed in the order they were received. When transferring between wallets, multiple transfer requests may be queued for the same asset in a given wallet, but only one will be processed at a time. The other requests will remain in the `QUEUED` state until the prior transfer is completed or fails.
#### Transferring Full Balance
For assets with network fees paid in a separate asset type, transferring the full balance of an asset is no different than transferring any other amount for that asset.
For assets with network fees paid in the same asset type, transferring the full balance is not possible without specifying to the server that the fee should be deducted from the transfer amount. See the `deductFeeFromAmountIfSameType` flag of the `TransfersRequest` model for more detail.
# Get transfer by ID
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/transfers/get-transfer-by-id
/knowledge-base/openapi/v2.yaml get /transfers/{transferId}
Permissions required: **Transfer funds**
Get transfer by ID. Restricted to transfers created by your API key, unless your API key's Transfer and Read permissions both cover the transfer's vault.
NOTE: price and USD value information is recent but does not reflect real-time data.
# List transfers
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/transfers/list-transfers
/knowledge-base/openapi/v2.yaml get /transfers
Permissions required: **Transfer funds**
List transfers created by your API key. For a given vault, transfers on it created by other API keys in your organization are also included if your API key's Transfer and Read permissions both cover that vault.
**Filters**
You may optionally supply the following filters:
- Set a date range by providing the `startDate` and/or `endDate` query parameters. If the date parameters are omitted, all transfers will be returned.
- Specify a specific vault to return transfers for by specifying the `vaultId` parameter. If the `vaultId` parameter is omitted, transfers originating from all vaults will be returned. Providing both `vaultId` and `walletId` filters will result in an error.
- Specify a specific wallet to return transfers for by specifying the `walletId` parameter. If the `walletId` parameter is omitted, transfers originating from all vaults and wallets will be returned. Providing both `vaultId` and `walletId` filters will result in an error.
- Filter transfers of one or more statuses with the `statuses` parameter. Multiple statuses should be separated by commas.
**Multiple Transfers**
To fetch a specific batch of transfers, pass a comma-separated list of `transferIds` as the `transferIds` query parameter.
# Cancel Trusted Destination creation
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/trusted-destinations/cancel-trusted-destination-creation
/knowledge-base/openapi/v2.yaml delete /trusted_destinations/{creationRequestId}/cancel
Permissions required: **Manage Trusted Destinations**
Cancel ongoing creation of Trusted Destinations
# Check status of Trusted Destinations
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/trusted-destinations/check-status-of-trusted-destinations
/knowledge-base/openapi/v2.yaml get /trusted_destinations/{creationRequestId}/status
Permissions required: **Read vault activity**
Check status of Trusted Destinations
# Create new Trusted Destinations
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/trusted-destinations/create-new-trusted-destinations
/knowledge-base/openapi/v2.yaml post /trusted_destinations
Permissions required: **Manage Trusted Destinations**
Create new Trusted Destinations
# Delete Trusted Destination
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/trusted-destinations/delete-trusted-destination
/knowledge-base/openapi/v2.yaml delete /trusted_destinations/{trustedDestinationId}
Permissions required: **Manage Trusted Destinations**
Delete a Trusted Destination
# List trusted destinations
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/trusted-destinations/list-trusted-destinations
/knowledge-base/openapi/v2.yaml get /trusted_destinations
Permissions required: **Read vault activity**
List trusted destinations
# Get vault by ID
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/vaults/get-vault-by-id
/knowledge-base/openapi/v2.yaml get /vaults/{vaultId}
Permissions required: **Read vault activity**
Get vault by ID
# List vaults
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/vaults/list-vaults
/knowledge-base/openapi/v2.yaml get /vaults
Permissions required: **Read vault activity**
List vault metadata including name, ID, description, and assets.
NOTE: price and USD value information is recent but does not reflect real-time data.
# Get vesting balances
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/vesting-balances-batch
POST /vesting/balances
Get vesting balances for multiple allocations.
# Get vesting balances for an allocation
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/vesting/get-vesting-balances-for-an-allocation
/knowledge-base/openapi/v2.yaml get /vesting/balances/{allocationId}
Get vesting balances for a specific allocation ID. Returns the current balance breakdown including available, unvested, and locked amounts.
# Activate an existing wallet on additional networks
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/wallets/activate-an-existing-wallet-on-additional-networks
/knowledge-base/openapi/v2.yaml post /wallets/{walletId}/activate
Permissions required: **Create address**
Activate the existing wallet identified by `walletId` on additional networks that share the same cryptographic key derivation (e.g. EVM-compatible chains). Each entry in `compatibleNetworkIds` produces a new wallet on that network with the same address as the source.
Per-network failures are reported individually in the response without aborting the whole call: a target network that is not key-compatible with the source wallet's network, or that the organization has not enabled, returns a `FAILED` status for that entry while other entries continue.
# Create a new wallet in a vault
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/wallets/create-a-new-wallet-in-a-vault
/knowledge-base/openapi/v2.yaml post /vaults/{vaultId}/wallets
Permissions required: **Create address**
Create a wallet in the specified `vaultId`.
# List all wallets for a vault
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/wallets/list-all-wallets-for-a-vault
/knowledge-base/openapi/v2.yaml get /vaults/{vaultId}/wallets
Permissions required: **Read vault activity**
Get all wallets for the specified `vaultId`.
# List all wallets for all vaults
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/wallets/list-all-wallets-for-all-vaults
/knowledge-base/openapi/v2.yaml get /wallets
Permissions required: **Read vault activity**
List wallet metadata for the current user.
# Staking positions for a wallet
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/wallets/staking-positions-for-a-wallet
/knowledge-base/openapi/v2.yaml get /wallets/{walletId}/staking/positions
Permissions required: **Read vault activity**
Get wallet staking positions details for the specified `walletId`.
# Staking rewards for a wallet
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/wallets/staking-rewards-for-a-wallet
/knowledge-base/openapi/v2.yaml get /wallets/{walletId}/staking/rewards
Permissions required: **Read vault activity**
Get wallet rewards details for the specified `walletId`.
# Wallet details for a wallet
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/wallets/wallet-details-for-a-wallet
/knowledge-base/openapi/v2.yaml get /wallets/{walletId}
Permissions required: **Read vault activity**
Get wallet details for the specified `walletId`.
# Cancel webhook subscription
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/webhook-notifications/cancel-webhook-subscription
/knowledge-base/openapi/v2.yaml delete /webhook/endpoints/{endpointId}/subscriptions/{eventTypeId}
Permissions required: **Configure Webhooks**
Cancel a webhook subscription to stop receiving notifications for its event type in its webhook endpoint.
# Create webhook endpoint
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/webhook-notifications/create-webhook-endpoint
/knowledge-base/openapi/v2.yaml post /webhook/endpoints
Permissions required: **Configure Webhooks**
Create a new endpoint where you would like to receive webhook notifications.
# Create webhook subscriptions
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/webhook-notifications/create-webhook-subscriptions
/knowledge-base/openapi/v2.yaml post /webhook/endpoints/{endpointId}/subscriptions
Permissions required: **Configure Webhooks**
Subscribe to event types to receive notifications in a webhook endpoint.
# Get webhook endpoint config
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/webhook-notifications/get-webhook-endpoint-config
/knowledge-base/openapi/v2.yaml get /webhook/endpoints/{endpointId}
Permissions required: **Configure Webhooks**
Get the configuration details for an endpoint.
# Get webhook validation key
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/webhook-notifications/get-webhook-validation-key
/knowledge-base/openapi/v2.yaml get /webhook/validation-key
Permissions required: **Configure Webhooks**
Get key to validate webhook authenticity.
# List webhook endpoint
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/webhook-notifications/list-webhook-endpoint
/knowledge-base/openapi/v2.yaml get /webhook/endpoints
Permissions required: **Configure Webhooks**
List all of your webhook endpoints.
# List webhook endpoint subscriptions
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/webhook-notifications/list-webhook-endpoint-subscriptions
/knowledge-base/openapi/v2.yaml get /webhook/endpoints/{endpointId}/subscriptions
Permissions required: **Configure Webhooks**
List the subscriptions that you configured for a webhook endpoint.
# List webhook event types
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/webhook-notifications/list-webhook-event-types
/knowledge-base/openapi/v2.yaml get /webhook/event-types
Permissions required: **Configure Webhooks**
List the available webhook event types that you can subscribe to.
# Update webhook endpoint
Source: https://docs.anchorage.com/knowledge-base/api-reference/v2/webhook-notifications/update-webhook-endpoint
/knowledge-base/openapi/v2.yaml patch /webhook/endpoints/{endpointId}
Permissions required: **Configure Webhooks**
Update the configuration for an endpoint.
# Connect your AI assistant
Source: https://docs.anchorage.com/knowledge-base/build-with-ai/connect-ai-assistant
Add Anchorage Digital docs to your AI tools through the hosted MCP server.
Connect our documentation to your AI assistant so it can answer questions and generate integration code grounded in the current docs. Anchorage Digital hosts a Model Context Protocol (MCP) server for this site.
## What the docs MCP server does
The MCP server lets your assistant search these docs and read pages on demand. It's read-only documentation knowledge—it can't access your account, keys, or funds, and it can't move assets. To take actions, your integration calls the REST API with your own scoped keys.
| Server | URL | Use for |
| :----------------- | :-------------------------------------- | :------------------------------------------------------------ |
| Public docs | `https://docs.anchorage.com/mcp` | Public documentation |
| Authenticated docs | `https://docs.anchorage.com/authed/mcp` | Documentation restricted to your account, after OAuth sign-in |
Opening `https://docs.anchorage.com/authed/mcp` directly in a browser returns `401 Unauthorized`. That endpoint is not a web page — it is an MCP transport, and authentication is browser-based OAuth triggered by your MCP client, not a token you paste in.
Add the URL to an MCP client that supports OAuth (Claude Desktop, Claude Code, Cursor, VS Code, ChatGPT). When the client first connects, it opens a browser window to sign in with your Anchorage Digital account. There are no client IDs, secrets, or long-lived tokens to configure. If your client doesn't open a sign-in window, it doesn't support OAuth — use `https://docs.anchorage.com/mcp` instead.
## Quick install
The fastest path is the one-line installer, which detects your installed tools:
```bash theme={null}
npx add-mcp https://docs.anchorage.com/mcp
```
You can also open the AI menu at the top of any docs page and choose an install option, such as Cursor, VS Code, or Copy MCP.
## Set up by tool
### Claude Code
```bash theme={null}
claude mcp add --transport http anchorage-docs https://docs.anchorage.com/mcp
```
### Claude Desktop and Claude web
In Settings, select **Connectors**, then select **Add custom connector**.
Enter a name and the URL `https://docs.anchorage.com/mcp`, then save.
### Cursor
Add the server to `mcp.json`:
```json theme={null}
{
"mcpServers": {
"anchorage-docs": {
"url": "https://docs.anchorage.com/mcp"
}
}
}
```
### VS Code (GitHub Copilot)
Add the server to `.vscode/mcp.json`:
```json theme={null}
{
"servers": {
"anchorage-docs": {
"type": "http",
"url": "https://docs.anchorage.com/mcp"
}
}
}
```
### ChatGPT and other clients
In any client that supports custom MCP connectors, add a new connector with the URL `https://docs.anchorage.com/mcp`. To include documentation restricted to your account, use `https://docs.anchorage.com/authed/mcp` and sign in when prompted.
The docs MCP server provides documentation only. It never has access to your API keys or the ability to move assets. See [AI security and guardrails](/knowledge-base/build-with-ai/security).
## Next steps
With your assistant connected, start from a [ready-made prompt](/knowledge-base/build-with-ai/prompts), or review the [security guardrails](/knowledge-base/build-with-ai/security) before you write code that moves assets.
# LLM-ready docs
Source: https://docs.anchorage.com/knowledge-base/build-with-ai/llm-ready-docs
Pull Anchorage Digital documentation into any AI tool as Markdown.
Every page in these docs is available as clean Markdown that AI tools can read. Use whichever method fits the size of the task—a single page, a product area, or the whole site.
## Copy or open any page
Every page has an AI menu at the top. Use it to copy the page as Markdown, view the raw Markdown, open the page in Claude, ChatGPT, Perplexity, or Google AI Studio, or add the docs to Cursor or VS Code.
## Get a page as Markdown
Append `.md` to any page URL to get its Markdown directly:
```text theme={null}
https://docs.anchorage.com/platform/developers/setting-up.md
```
This is the cleanest way to hand one page to an AI tool or fetch it programmatically.
## Get the whole site
We publish the entire documentation set as a single file for LLM ingestion:
```text theme={null}
https://docs.anchorage.com/llms-full.txt
```
The same file is mirrored at `https://docs.anchorage.com/.well-known/llms-full.txt`.
`llms-full.txt` is large and can exceed an AI tool's context window. For focused work, connect the [MCP server](/knowledge-base/build-with-ai/connect-ai-assistant) or copy only the pages you need.
## Which method to use
| You need | Use |
| :--------------------------------- | :------------------------------------------------------------------- |
| One page | The AI menu, or append `.md` to the URL |
| A product area, searched on demand | The [MCP server](/knowledge-base/build-with-ai/connect-ai-assistant) |
| The full documentation set | `llms-full.txt` |
# Build with AI
Source: https://docs.anchorage.com/knowledge-base/build-with-ai/overview
Use AI assistants and coding agents to learn and integrate with Anchorage Digital faster.
You can explore these docs and build your Anchorage Digital integration with AI assistants and coding agents. Ask questions in natural language, pull our documentation straight into your AI tool, and start from ready-made prompts—while keeping the guardrails a custodian requires.
## What you can do
Add our docs to Claude, Cursor, VS Code, and more through the hosted MCP server.
Copy any page as Markdown, open it in your AI tool, or pull the whole site.
Start common integrations from copy-paste prompts.
Keep AI agents safe when they touch institutional assets.
## New to AI-assisted development?
An **AI coding assistant**—such as Claude, Cursor, GitHub Copilot, or Windsurf—writes and edits code alongside you. The **Model Context Protocol (MCP)** is an open standard that connects these assistants to outside knowledge and tools, like a universal adapter. The assistant is the **client**; a **server** supplies the knowledge or actions. Anchorage Digital hosts an MCP server for these docs, so your assistant can search and cite them directly instead of guessing.
## Recommended path
Use Claude Code, Cursor, VS Code with Copilot, Windsurf, or the Claude and ChatGPT apps.
Add our MCP server, or pull pages as Markdown, so your assistant answers from the current docs rather than guesswork. See [Connect your AI assistant](/knowledge-base/build-with-ai/connect-ai-assistant).
Use a ready-made prompt for your task. See [Ready-made prompts](/knowledge-base/build-with-ai/prompts).
Use scoped, read-only keys first, and keep a human in the loop before anything moves assets. See [AI security and guardrails](/knowledge-base/build-with-ai/security).
Anchorage Digital moves institutional assets. Before you let an AI agent act on your account, read [AI security and guardrails](/knowledge-base/build-with-ai/security).
## Related
* [Set up API access](/knowledge-base/platform/developers/setting-up) — Create permission groups and keys, and sign requests.
* [API reference](/knowledge-base/api-reference/introduction) — The full REST API, generated from the OpenAPI spec.
# Ready-made prompts
Source: https://docs.anchorage.com/knowledge-base/build-with-ai/prompts
Start common Anchorage Digital integrations from copy-paste AI prompts.
Copy these prompts into your AI assistant to scaffold common integrations. For the best results, connect the [docs MCP server](/knowledge-base/build-with-ai/connect-ai-assistant) first so the assistant works from the current documentation.
## Integration prompts
You are helping build an integration with the Anchorage Digital REST API (base URL [https://api.anchorage.com/v2](https://api.anchorage.com/v2)). Using the Anchorage Digital documentation, scaffold a typed API client that authenticates with the `Api-Access-Key` header and signs sensitive requests with an Ed25519 `Api-Signature` and `Api-Timestamp`. Cite the specific documentation pages you rely on, and confirm the current endpoint paths from the docs rather than assuming them.
Using the Anchorage Digital documentation, outline and implement the steps to withdraw a digital asset: creating a permission group, generating an API key, adding a trusted destination, and submitting the withdrawal. Call out every step that requires quorum approval, and do not bypass human approval. Verify each endpoint against the docs before writing code.
Using the Anchorage Digital documentation, help me subscribe to and verify webhooks for transfer and deposit events. Show how to validate webhook signatures and how to reconcile each event with the read APIs.
Using the Anchorage Digital documentation, implement a stablecoin mint, redeem, and bridge with the conversion endpoint, and explain how to track each conversion to completion. Confirm the exact asset-type strings from the docs.
## Keep prompts available in your tool
To reuse guidance across a project, save it in your tool's rules or instructions file:
| Tool | Where to add project instructions |
| :------------- | :---------------------------------------------- |
| Claude Code | `CLAUDE.md` or `AGENTS.md` in your project root |
| Cursor | Project rules in `.cursor/rules` |
| GitHub Copilot | `.github/copilot-instructions.md` |
| Windsurf | Workspace rules in `.windsurf/rules` |
Exact file names change as tools evolve. Confirm the current path in your AI tool's documentation.
## Write your own
Effective prompts share a few habits: point the assistant at our docs or the MCP server, name the exact task, ask it to cite the pages it used, and tell it to verify endpoints and asset types against the docs rather than relying on memory.
Always review AI-generated code before running it, and test in the [sandbox](/knowledge-base/platform/developers/sandbox/sandbox-overview) before production. See [AI security and guardrails](/knowledge-base/build-with-ai/security).
# AI security and guardrails
Source: https://docs.anchorage.com/knowledge-base/build-with-ai/security
Keep AI assistants and agents safe when building on Anchorage Digital.
AI tools speed up integration, but you're operating on institutional assets. These guardrails keep AI assistants and autonomous agents from causing harm.
## The docs MCP server is read-only
Our documentation MCP server only searches and returns docs. It has no access to your keys, account, or funds, and it can't move assets. Connecting it is safe.
## Use least-privilege API keys
Give AI-assisted code only the access it needs. Scope keys with [permission groups](/knowledge-base/platform/developers/permission-groups), and start with read-only keys while you explore. Keep internal and external transfer permissions in separate permission groups and keys.
## Keep a human in the loop for asset movement
Withdrawals and external transfers require quorum approval by design—never let an agent approve them. Treat every asset-moving action as human-approved, not automated. See [vault policies](/knowledge-base/platform/users/vault-policies) and the [move money overview](/knowledge-base/platform/developers/move-money/overview).
## Protect keys and signing material
Never paste API keys, private keys, or signing secrets into a prompt or chat. Keep them out of your AI tool's context and in your secrets manager. Sensitive endpoints require an Ed25519 signature—generate signatures in your own environment. See [Request signing](/knowledge-base/platform/developers/request-signing).
## Treat AI output as untrusted
* Review generated code before you run it.
* Test against the [sandbox](/knowledge-base/platform/developers/sandbox/sandbox-overview) before production.
* Watch for prompt injection: content an agent fetches from the web can carry hidden instructions, so don't act on it blindly.
* Verify before you sign or broadcast any transaction.
## Verify against current docs
AI models can generate outdated API patterns. Have your assistant cite the documentation pages it used, and confirm endpoint paths and asset types against the current docs or the [MCP server](/knowledge-base/build-with-ai/connect-ai-assistant).
# Home
Source: https://docs.anchorage.com/knowledge-base/index
Run your business on a full-stack platform for digital assets. Anchorage Digital provides the complete infrastructure stack for institutions to participate in the digital asset economy.
Anchorage Digital Knowledge Base
Guides and documentation
Anchorage Digital provides the complete infrastructure stack for
institutions to participate in the digital asset economy.
"Anchorage Digital" refers to services that are offered through the wholly-owned subsidiaries of Anchor Labs, Inc., a Delaware corporation.
Anchorage Digital does not provide legal, tax, or investment advice. Anchorage Digital is not engaged in the business of the offer, sales, or trading of securities and is not registered with the SEC.
Holdings of cryptocurrencies and other digital assets are speculative and involve a substantial degree of risk, including the risk of complete loss. There can be no assurance that any cryptocurrency, token, coin, or other crypto asset will be viable, liquid, or solvent. No Anchorage Digital communication is intended to imply that any digital asset services are low-risk or risk-free. Anchorage Digital endeavors to provide accurate information on this website, but cannot guarantee all content is correct, complete, or updated.
Digital assets held in custody are not guaranteed by Anchorage Digital and are not subject to the insurance protections of the Federal Deposit Insurance Corporation ("FDIC") or the Securities Investor Protection Corporation ("SIPC"), or the Singapore Deposit Insurance Corporation ("SDIC"). Anchorage Digital Singapore is not a member of the Singapore Deposit Insurance ("DI") Scheme and assets are not subject to the protections enjoyed by depositors with DI Scheme member institutions.
Agency trading services are provided by Anchorage Hold LLC. A1 Ltd. is a principal trading business.
# Account hierarchy
Source: https://docs.anchorage.com/knowledge-base/platform/developers/account-hierarchy
Understand Anchorage Digital's hierarchical model for organizations, accounts, vaults, wallets, and balances.
Anchorage Digital's security model uses a hierarchical structure for organizational entities and crypto assets. Each level has unique properties, allowing for flexible configurations to meet your organization's needs. While all use cases are unique, each maintains consistent structural rules. The following diagram provides an overview of each:
## Organizations
At Anchorage Digital, the **organization** is the highest hierarchical classification within the product, where a client or partner of Anchorage Digital is onboarded. Clients may have one or many accounts under each organization.
## Accounts
Each organization can have multiple **accounts**. Each account can be its own legal entity under the parent organization, or a part of the legal parent organization. This enables parent organizations to onboard separate business entities while maintaining separate ownership of assets at the account level.
Accounts can also be used to onboard end customers (program customers) under the control of the middle-B partner (partner platform) for business-to-business-to-business (B2B2B) or business-to-business-to-consumer (B2B2C) use cases. For more information, contact our client experience team at [accountexecutive@anchorage.com](mailto:accountexecutive@anchorage.com).
## Vaults
Under each account, there may be one or many **vaults**. A vault is Anchorage Digital's way of organizing asset wallets and user and API key permissions. If the organization has multiple vaults, each one can be managed by the same or separate admins on the account.
Each vault has its own security and quorum approval policy. Admins elect who manages each vault and how many vault members constitute a quorum for sensitive transactions or activities within the vault. Vaults can hold single or multiple assets, depending on the use case. Each vault also has its own `vaultId`, used to request or filter API responses, including withdrawals, trades, and transfers.
The `vaultId` is uniquely identifiable across the Anchorage Digital platform and can be used to reference a vault using Anchorage Digital's APIs. You can find the `vaultId` field by hitting the list vaults endpoint. Only the vaults provisioned on the API key are returned.
### View your account structure
Wallets hold balances for a specific asset within a vault, and each vault can contain multiple wallets—one per asset type. As you map your account structure, use `GET /v2/wallets` to list every wallet your API key can access across all permissioned vaults.
## Wallets
Under each vault, there may be multiple **wallets**. A wallet at Anchorage Digital is similar to a traditional crypto wallet, with slight nuances to match the structure of Anchorage Digital's platform capabilities and services.
Anchorage Digital wallets are tied to a particular blockchain and serve as a flexible way to aggregate and manage assets. This removes the complexity and need for users to manage multiple addresses, while maintaining the ability to trace assets and view separate on-chain interactions. There may also be multiple wallets on the same blockchain within the same vault, if needed to support the use case.
### Wallet creation
All active members of a vault can create a wallet via the create wallet API, which doesn't require quorum approval. Wallet addresses can be reused, although they can't be deleted once generated in a vault, as they remain live on the blockchain.
If a vault is ever deleted, ensure individuals—including counterparties—with access to wallet addresses refrain from sending additional assets to the deleted vault. If a deposit is made to an address under a deleted vault, Anchorage Digital can reactivate it to retrieve the assets.
### Default wallet
If there are multiple wallets for the same blockchain within a single vault, the first wallet created for each specific blockchain is designated as the **default wallet**. The following operations require the default wallet, as these are specified at the vault level and the default wallet is the source of funds:
* External withdrawals
* Settlement of funds from Anchorage Digital trading into client vaults
* Execution of a hold via API
### UTXO vs. account-based wallets
Anchorage Digital uses various asset wallet models: account-based and unspent transaction output (UTXO) wallets. The conceptual difference is that the account model updates user balances globally.
The UTXO model only records transaction receipts. In the UTXO model, account balances are calculated on the client side by adding up the available unspent transaction outputs (UTXOs).
When a transaction uses more funds than needed from a source address, the remainder (or "change") is sent to a new change address within the wallet. These change addresses are automatically managed and are part of the wallet's balance.
| Type | Account-based wallets | UTXO wallets |
| :--------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Definition | Contain one address for multiple assets on the same blockchain. The transaction model is similar to spending on an ATM card, where the balance is reduced by the exact amount spent. This keeps track of each account's balance as a global state. | Take into account the unspent transaction output, where a single input results in a new unspent balance and a net-new address created within the wallet each time this occurs. This is similar to using a one dollar bill and getting change in return. |
| Example | An Ethereum-based wallet with a single address for ETH and ERC-20s (e.g. USDC). | A Bitcoin wallet with multiple addresses for the same BTC wallet, each with individual on-chain balances, but pooled together for transactions and transfers. |
| Additional notes | The address is the only deposit address across all tokens within the wallet (e.g. ETH and USDC). Asset-specific balances, transfers, and transactions are accessible in the iOS app, web dashboard, and on-chain using blockchain explorers. | During a transfer or transaction, funds are automatically pulled from multiple source addresses—you don't need to designate addresses. All addresses created can be used as deposit addresses at Anchorage Digital. |
## Balances
Each asset in an Anchorage Digital vault contains an `availableBalance` and a `totalBalance`:
* `availableBalance` is the balance of funds available to be withdrawn or transferred. Use this value when reading balances for client balance monitoring or evaluating sufficient client funds. This balance excludes any funds that are held, in progress, or locked.
* `totalBalance` is the total amount of assets under custody within the vault. This balance may contain funds that are in progress or locked for activities like voting. It's always greater than or equal to the `availableBalance`.
# Exploring account structures
Source: https://docs.anchorage.com/knowledge-base/platform/developers/account-structure-explorer
Compare FBO and omnibus account structures across disclosure and attribution models on both the crypto and USD rails.
# Exploring account structures
Infrastructure Services account structures are usually described as single labels—"pure omnibus," "FBO," "virtual accounts"—but each label bundles three independent decisions. This explorer separates them so you can flip one at a time and watch the same deposit take a different path through the books.
## The three switches
Each switch answers a different question, and you can move them almost independently.
* **FBO or omnibus**—a question of legal title: who the money belongs to at the account level.
* **Disclosed or undisclosed**—a question of compliance: who runs know your customer (KYC) checks on the end user.
* **Subaccounting or virtual accounting**—a question of source of truth: whose ledger is authoritative for each customer's balance.
Switches 1 and 3 have one dependency between them. FBO title passes beneficial interest through to named beneficiaries, and an ownership right can't pass through to a share we don't track. Virtual accounting puts that share on the client's own ledger, so there's nothing at Anchorage Digital for the titled interest to attach to. Selecting **FBO** therefore holds attribution at **Subaccounting**, and **Virtual** is unavailable until you switch back to **Omnibus**.
The rail switch changes the mechanics that carry the money: a Fedwire transfer into a correspondent account for USD, or an on-chain transfer into a vault for crypto. Attribution differs by rail—USD deposits are told apart by a virtual account number or an FFC reference, while crypto deposits are told apart by deposit address, never by memo.
## Reading the diagram
Solid lines are movement of value. Dashed lines are oversight and reconciliation. The line that animates is the one active in the current step, so stepping through the flow shows the order in which each book posts. The deposit runs left to right along the upper track — customer, rail, custody — and the withdrawal returns along the lower one.
Play, step, and reset sit directly above the chart. Three panels then overlay it as you move through the flow:
* **The step callout** appears over the lower left, naming the current step and what it does. It changes as you step.
* **The books** sits at the bottom right and appends entries as each step fires, so you can watch the same deposit hit the correspondent statement or chain, the general ledger, and the customer book in sequence. It covers the ledger boxes it describes, so **Hide** collapses it to a header bar when you want the chart unobstructed.
* **Structure · Disclosure · Attribution** sits at the bottom left, restating what the three switches currently mean.
Below the chart, **Who holds what** turns the same configuration into a set of obligations: legal title, compliance ownership, source of truth, and where the funds availability check happens.
Ben Okafor and Chloe Kim are ghosted above Ana and never move. They are there because the pool holds their balances too — which is precisely what makes the attribution question matter.
The starred **Source of truth** badge marks the switch that matters most operationally. Under subaccounting, a payout larger than the customer's own balance is rejected even when the pool has funds. Under virtual accounting, the pool clears the payout and enforcing each customer's limit stays with the client.
## What this page doesn't decide
The seven coherent switch combinations render here for teaching purposes. Which structures Anchorage Digital actually offers, and in which phase, is a product decision rather than a property of the mechanics. The eighth combination is excluded for a mechanical reason, not a product one: FBO can't ride on virtual accounting.
For the structures available today and the approvals each one needs, see [B2B2X accounts](/knowledge-base/platform/developers/b2b2x). For the client-facing version of the same material, see [B2B2X account structures](/knowledge-base/platform/users/b2b2x-accounts).
# API keys
Source: https://docs.anchorage.com/knowledge-base/platform/developers/api-keys
Generate, use, check, revoke, and rotate API access keys to authenticate requests to the Anchorage Digital API.
An API key authenticates your requests to the Anchorage Digital API. Each key is scoped to a [permission group](/knowledge-base/platform/developers/permission-groups) that defines what it can do, so create the group you need before you generate the key.
## How to generate an API key
In the **Developers**, then **API 2.0** section of the web dashboard, select **Create API key**.
The web dashboard supports in-app key generation, or you can bring your own keys. Use the widget below to generate a key pair in this browser session, or run the Python script manually.
This in-app widget is intended for staging and testing only. For production key pairs, use the Python script below or your own key generation tooling instead.
We can't yet guarantee we have every control in place to safely generate and handle keys on your behalf. Generating your own keys keeps that risk with you, rather than shifting it to Anchorage Digital.
```python theme={null}
# https://pypi.org/project/PyNaCl/
import nacl
import nacl.signing
import secrets
seed = secrets.token_bytes(32)
signing_key = nacl.signing.SigningKey(seed)
print('Signing key:')
print(signing_key.encode().hex())
print('Public key:')
print(signing_key.verify_key.encode().hex())
```
Select the permission group you created, and use the public key from the previous step to create your API key. Selecting certain permission groups requires additional quorum approval before the key can be used.
Copy the API key immediately — it isn't displayed again, and keys aren't recoverable. If you lose a key, revoke it and generate a new one.
When you create a key, you'll work with three values:
1. **API access key** — sent on every request as `Api-Access-Key`.
2. **Ed25519 public key** — registered during key generation. Use the Anchorage Digital-generated one or bring your own.
3. **Ed25519 private signing key** — kept locally to produce signatures before a call.
## Using an API key
Every request is made over HTTPS and includes your access key in the `Api-Access-Key` header.
```bash theme={null}
curl --request GET \
--url https://api.anchorage-staging.com/v2/apikey \
--header 'Api-Access-Key: '
```
Sensitive endpoints also require a request signature, passed as `Api-Timestamp` and `Api-Signature`.
```bash theme={null}
curl --request POST \
--url https://api.anchorage-staging.com/v2/transactions/withdrawal \
--header 'Api-Access-Key: ' \
--header 'Api-Signature: ' \
--header 'Api-Timestamp: ' \
--header 'Content-Type: application/json' \
--data '
{
"amount": "1000.00000000",
"assetType": "BTC",
"description": "Internal ID: #12838927347",
"idempotentId": "",
"useGasStation": true
}
'
```
See [Signing requests](/knowledge-base/platform/developers/request-signing) for the full signature recipe before making sensitive calls.
## Checking API key status and activity
Before you revoke or rotate a key, confirm whether it's still active and whether anything is using it. Anyone with web dashboard access can run these checks — no engineering support needed.
### From the web dashboard
In the **Developers**, then **API 2.0** section of the web dashboard, your organization's API keys are listed with their details. Review a key's details to confirm whether it's active and whether it has been used.
### From the API
A key can also verify itself. Call `GET /v2/apikey` with the key — a successful response confirms the key is active and returns its details, including the permissions it holds.
```bash theme={null}
curl --request GET \
--url https://api.anchorage-staging.com/v2/apikey \
--header 'Api-Access-Key: '
```
If the key was revoked, the request fails authentication instead of returning key details.
If a key is active but no longer in use, revoke it — an unused active key is unnecessary standing access.
## Revoking an API key
To revoke a single key, select the three-dot menu next to the key and select **Revoke**. To revoke every key in a group at once, delete the [permission group](/knowledge-base/platform/developers/permission-groups) the keys belong to.
## Rotating API keys
There's no dedicated rotation endpoint. You rotate a key yourself by revoking the active key and creating a new one tied to the permission group you want.
Generate a new API key and assign it to the desired permission group, following the steps above. Update your integration to use the new key.
Once the new key is in place and confirmed working, revoke the previous key.
Rotate keys on a regular schedule, and immediately if a key may have been exposed. Creating the replacement before revoking the old key avoids any gap in access.
# Atlas collateral management
Source: https://docs.anchorage.com/knowledge-base/platform/developers/atlas/atlas-collateral-management
Reference guide for Anchorage Digital's Atlas collateral management service, including key concepts, transaction lifecycle, operations management, and notifications.
Anchorage Digital's Atlas collateral management is an agency service for institutional lenders and borrowers engaged in crypto-secured transactions. The service mitigates counterparty risk and reduces operational overhead by combining regulated custody with automated risk monitoring.
Typically, Anchorage Innovations LLC acts as the collateral manager (agent), while Anchorage Digital Bank, N.A. (an OCC-chartered federal trust bank) or Anchorage Digital Singapore Pte. Ltd. (licensed by MAS) acts as the Custodian.
***
## Communications
**Approved channels**
All communications in connection with Collateral management services are made over email:
* **General communication:** [admin-collateralmanagement@anchorage.com](mailto:admin-collateralmanagement@anchorage.com)
* **Notices, urgent items, or operations submissions:** [collateralmanagement@anchorage.com](mailto:collateralmanagement@anchorage.com)
**Collateral management team**
The Anchorage Digital Collateral Management team is responsible for monitoring transaction health, issuing margin calls and other notices, initiating transfers of collateral assets, and providing reporting.
***
## Key terminology
### Participants
* **Pledgor:** The borrower or counterparty who provides digital assets as collateral to secure an obligation.
* **Secured party:** The institution or lender who provides credit and receives collateral from a Pledgor.
* **Collateral manager:** Third-party role fulfilled by Anchorage Digital, combining the Custodian (holding assets) and the collateral manager (monitoring risk).
### Transaction components
* **Exposure:** The outstanding transaction or obligation being secured, such as a loan or repo.
* **Collateral package:** The collection of assets pledged by a Pledgor to secure an Exposure. This is the primary object for monitoring.
* **Risk metrics (LTV):** The critical metric measuring the ratio of the Exposure to the weighted value of the collateral. The system calculates LTV in near real-time.
### States
The current condition of a collateral package, determined by its LTV against predefined thresholds.
* **Healthy:** Collateral levels do not require action — LTV falls between the margin return and margin call thresholds.
* **Margin return:** Pledgor is eligible for a return of collateral. Action taken upon entering this state: None or Sweep.
* **Margin call:** Pledgor is required to top up collateral within the defined cure period to bring the LTV back to the return-to-LTV level. If the cure period expires before a valid top-up is received, action taken: None, Full, Partial, or Sweep.
* **Critical:** Unless cure period protection is configured and the cure period has not expired, the system immediately takes action: None, Full Liquidation, Partial Liquidation, or Sweep.
### Actions
A pre-configured, automated response the system executes when a Collateral Package enters a specific state.
* **None:** Notify both parties.
* **Full liquidation:** Full liquidation of collateral and repayment of the loan, reducing both Exposure and collateral value to zero.
* **Partial liquidation:** Partial liquidation of collateral and partial repayment of the loan in the amount that brings the LTV back to a healthy state.
* **Sweep:** Move the entire collateral balance to the Secured Party, reducing both Exposure and collateral value to zero.
### Concepts and inputs
* **Cure period:** A configurable grace period (in hours) following a margin call, during which a Pledgor can deposit additional collateral to resolve a shortfall before a default action is taken.
* **Return-to-LTV:** A specific LTV target a collateral package must reach to return to a healthy state after a non-healthy state change. If the price of an asset changes during transit, the quantity sent may be insufficient to cure the state by the time it is received.
* **Warning level:** Each LTV threshold can have a warning level configured inside the relevant threshold. Upon breach, Anchorage Digital notifies both parties that the threshold is approaching.
* **Operation:** A record in the system's transaction log indicating a change in a collateral balance (e.g., `TOP_UP`) or an Exposure balance (e.g., `PAY_DOWN`).
***
## Transaction lifecycle
1. **Setup & configuration:** The secured party and pledgor execute bilateral transaction agreements and provide transaction details and risk parameters to Anchorage Digital, including LTV thresholds, eligible assets, cure periods, and predefined actions.
2. **Funding:** The pledgor deposits the required collateral into their segregated vault/wallet at the designated Anchorage Digital custodian. The secured party funds the loan/exposure and notifies the Anchorage Digital collateral management team.
3. **Monitoring:** The system begins 24/7 automated monitoring, calculating LTV in near real-time.
4. **Threshold events:** If the LTV breaches a configured threshold, the system automatically takes the predefined action — warning notification, margin call, critical liquidation, or margin return.
5. **Resolution & reporting:** If a margin call occurs, the pledgor submits a `TOP_UP` operation to deposit additional collateral and satisfy the return-to-LTV requirement. If the margin call is not cured or a critical threshold is breached, Anchorage Digital coordinates collateral liquidation via its trading desks. Participants have continuous access to package status via API and dashboard.
***
## Asset pricing for valuation
The Atlas collateral management system uses four primary parameters to determine real-time asset valuation within a collateral package. These settings define the data pipeline and logic used to calculate the LTV ratio.
If the price source becomes unavailable or Anchorage Digital reasonably determines that prices are unreliable due to low or inconsistent trading volumes or other factors, Anchorage Digital may use an alternative source at its reasonable sole discretion.
**Price source provider**
The upstream data aggregator or oracle used to fetch market data. Amberdata is used for centralized exchange (CEX) market data aggregation; Chainlink is used for decentralized, on-chain price feeds.
**Price cource**
The exact venue or data feed queried from the selected provider. Most major exchanges are supported.
**Back-up pricing**
If a primary price source becomes unavailable or diverges from the prevailing market price, the system automatically transitions to a backup feed from a reputable commercial provider.
**Pricing type**
The specific metric extracted from the price source's order book or trade history to establish the asset's current system value: **Bid** (highest outstanding buy order), **Ask** (lowest outstanding sell order), **Mid** (median between Bid and Ask), **Last** (price of the most recently matched trade), or **Default** (used for Chainlink and index data feeds).
**Asset weight**
A numerical parameter that applies a risk discount (haircut) to the calculated market value of an asset before it is aggregated into the total collateral package value. Configurable from 0% to 100%. For example, if an asset's spot price is $1,000 and the weight is configured to 80%, the system recognizes $800 of value per unit for LTV calculations.
***
## Operations management
Operations modify the balances of the collateral package and/or the exposure. Anchorage Digital automatically books operations it is aware of, such as additional collateral deposits and collateral returns.
For operations Anchorage Digital may not be aware of — such as a lender sending fiat loan principal to the borrower through traditional rails — the appropriate party must notify Anchorage Digital via API or an authorized email address.
### Collateral operations
| Operation | Effect | Description |
| :------------------------- | :--------------------------- | :-------------------------------------------------------------------------------------------------- |
| `INITIAL_DEPOSIT` | Increases collateral balance | First collateral deposit. |
| `TOP_UP` | Increases collateral balance | Adds collateral, often in response to a margin call. |
| `MARGIN_RETURN` | Decreases collateral balance | Excess collateral returned to the Pledgor. |
| `CLOSE_RETURN` | Reduces collateral to zero | Full collateral return at the conclusion of a lending arrangement. |
| `REHYPE_OUT` / `REHYPE_IN` | Logs rehypothecation | Records when collateral has been rehypothecated out of or returned to its original custody account. |
| `GAS_FEE` | Records on-chain costs | Captures costs for on-chain withdrawal or deposit related to collateral operations. |
### Exposure operations
| Operation | Effect | Description |
| :----------------- | :------------------------- | :-------------------------------------------------------------------------------- |
| `INITIAL_FUNDING` | Increases exposure | Initial loan amount. |
| `PAY_UP` | Increases exposure | Upsize in the loan. |
| `PAY_DOWN` | Decreases exposure | Partial loan repayment. |
| `INTEREST_ACCRUAL` | Increases exposure | Accounts for accrued interest. |
| `INTEREST_PAYDOWN` | Decreases exposure | Accrued interest payment. |
| `CLOSE` | Decreases exposure to zero | Full repayment. |
| `GAS_FEE` | Records on-chain costs | Captures costs for on-chain withdrawal or deposit related to exposure operations. |
### Liquidation operations (system-generated)
| Operation | Description |
| :-------------------- | :--------------------------------------------------------------------------------------------- |
| `FULL_LIQUIDATION` | Reduces both exposure and collateral to zero after a complete sale of collateral. |
| `PARTIAL_LIQUIDATION` | Reduces exposure and collateral by the amount needed to bring the LTV back to a healthy state. |
| `SWEEP` | Transfers the entire collateral balance to the secured party, reducing both balances to zero. |
***
## Liquidations monitoring & management
Anchorage Digital provides liquidation capabilities through the Atlas platform, designed to protect the secured party's interests through real-time monitoring and rapid execution.
**Monitoring and triggering**
The platform features 24/7 monitoring with real-time price updates for all collateralized assets. Alerts for warnings, margin calls, returns, and critical states are sent in real-time via email and API to both parties and the Anchorage Digital team. Redundant SMS, voice, and email alerts ensure immediate awareness and execution.
**Order management and liquidity**
Multiple liquidation orders are handled on a first-in, first-out (FIFO) basis, determined by the exact timestamp the liquidation was triggered. Anchorage Digital aggregates liquidity from major market makers and trades against the best available price unless otherwise agreed.
***
## Participant email configuration
Three distinct email lists are configured per participant to direct communications to the appropriate stakeholders.
| Email list | Field | Purpose |
| :------------ | :--------------------- | :-------------------------------------------------------------------------------------------------------------------------------------- |
| Notification | `notice_emails` | High-priority, time-sensitive alerts and formal notices — including margin calls, cure period expirations, and default notices. |
| Reporting | `reporting_emails` | Standard periodic reporting, such as daily or monthly collateral valuation summaries. |
| Configuration | `configuration_emails` | Authorized addresses permitted to provide ad-hoc instructions or submit CSV files to update thresholds, assets, or participant details. |
***
## Email and webhook notifications
The collateral management system sends email notices to the secured party and pledgor for specific events, subject to internal logic that prevents alert fatigue.
* **Warning levels:** Warning LTV thresholds can be configured inside the margin call and critical state thresholds. Warnings are sent at most once every 24 hours.
* **State transitions:** An email is sent immediately upon transition to healthy, margin return, margin call, or critical state. These emails include current LTV, thresholds, return-to-LTV targets, suggested action amounts, and cure period deadlines.
* **Cure period expiry:** A notification is sent upon cure period expiry detailing the impending action (full liquidation, partial liquidation, or sweep).
* **Webhooks:** Webhook notifications can be configured for state transitions, providing the same real-time information and metadata as email notifications.
# Settlement API integration guide
Source: https://docs.anchorage.com/knowledge-base/platform/developers/atlas/atlas-settlement-api
Integrate with the Atlas settlement network API to propose, accept, authorize, and monitor settlements between participants.
The Atlas settlement network supports four core settlement workflows. Atlas Plus organizations have access to all workflows; standard Atlas organizations can perform withdrawal to a trusted counterparty and one-way settlements.
| Settlement workflow | Atlas | Atlas Plus |
| :--------------------------------- | :---: | :--------: |
| Withdrawal to trusted counterparty | ✔ | ✔ |
| Send funds (one-way) | ✔ | ✔ |
| Receive funds (one-way) | ✔ | ✔ |
| Send and receive (two-way) | — | ✔ |
USD is supported across all Atlas settlement workflows (UI and API). USD is treated as another asset within a wallet for the purposes of settlement. No network fees apply for USD settlement legs.
***
## Prerequisites
Before integrating with the Atlas settlement network API, complete the following setup steps in the Anchorage Digital web dashboard:
* Create your API key permission group and API key. See [API keys](/knowledge-base/platform/developers/api-keys) and [Permission groups](/knowledge-base/platform/developers/permission-groups).
* Create a Shared API key.
* Set up and configure your participant vault. See **Atlas participants** in the web dashboard under **Settings**.
* Collect trusted counterparty IDs from all counterparties you will be transacting with.
***
## Atlas endpoints
| Endpoint | Required permissions | Overview | Notes |
| :---------------------------------------------------------------------------------------------------------------------- | :----------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [Propose a settlement](/knowledge-base/api-reference/endpoints/atlas/propose-settlement) | Propose and accept settlements | Propose a settlement with a counterparty for assets coming from and/or arriving into wallets owned by your participant. | Positive amounts indicate funds to be received; negative amounts indicate funds to be sent. |
| [Authorize a settlement](/knowledge-base/api-reference/endpoints/atlas/authorize-settlement) | Authorize settlements | After proposing or accepting a settlement, the settlement details must be authorized. | To authorize via API, the API key must have the `Authorize settlement` permission. Otherwise, authorization takes place in the app according to organization policy. |
| [Accept a settlement](/knowledge-base/api-reference/endpoints/atlas/accept-settlement) | Propose and accept settlements | Accept a proposed settlement and select wallets to receive funds to and/or send funds from. | Use positive numbers for assets to receive and negative for assets to send. The sum of amounts, by asset type, must exactly match the negative of the proposer's amounts. The special string `createWallet` can be used to create a new wallet for this asset. |
| [Reject a proposed settlement](/knowledge-base/api-reference/endpoints/atlas/reject-settlement) | Propose and accept settlements | Reject a settlement proposed to your participant, or cancel the authorization of a settlement you have already accepted. Proposed settlements that have been authorized by both parties (`Executing` or `Executed` state) cannot be canceled. | To reject an authorization via API, the API key must have the `Authorize settlement` permission. |
| [List settlements](/knowledge-base/api-reference/v2/atlas-settlement-network/list-settlements) | Read vault activity | Get settlements proposed by you or proposed to you. | |
| [Get settlement by ID](/knowledge-base/api-reference/v2/atlas-settlement-network/get-settlement-by-id) | Read vault activity | Get a single settlement by its ID. | |
| [Get counterparty details by ID](/knowledge-base/api-reference/v2/atlas-settlement-network/get-counterparty-by-id) | Read vault activity | List details about a specific counterparty. | |
| [List my trusted counterparties](/knowledge-base/api-reference/v2/atlas-settlement-network/list-trusted-counterparties) | Read vault activity | List all trusted counterparties. | |
| [Get participant by ID](/knowledge-base/api-reference/v2/atlas-settlement-network/get-participant-by-id) | Read vault activity | Get a single participant by its ID. | |
| [List participants](/knowledge-base/api-reference/v2/atlas-settlement-network/list-participants) | Read vault activity | Get the list of participants you have access to. | |
The `createWallet` string is only available for the Accept a settlement endpoint. It indicates that a new wallet should be created for the specified asset during the settlement.
***
## Critical IDs
| ID | Details |
| :------------------ | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `participantId` | The ID associated with your participant account. Counterparties use this ID to find you and initiate settlements. Your participant name is visible to other network participants when they search by participant ID — contact your client experience manager to use a different display name. |
| `proposerId` | The participant ID of whoever proposed the settlement. |
| `acceptorId` | The participant ID of whoever is accepting the settlement. |
| `settlementId` | The unique ID associated with each settlement. Used to query settlements via API. |
| `idempotentId` | See the idempotency section in the API documentation. |
| `clientReferenceId` | A unique ID created by the proposing client. Can be any alphanumeric string. |
| `vaultId` | The vault ID of the sending party. Use List Vaults to retrieve. |
| `walletId` | The wallet ID of the sending party. Use List Wallets to retrieve. |
***
## Getting started
### 1. API permission group
Set up an API permission group for Atlas settlement operations. See [Permission groups](/knowledge-base/platform/developers/permission-groups) for general setup instructions.
**Recommended permissions:**
| | Global (org-wide) | Vault-level |
| :----------- | :------------------------------------------------------------------------------------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------ |
| **Required** | N/A | `Read`, `Propose and Accept Settlements`, `Authorize Settlements` |
| **Optional** | `Initiate withdrawal` — enables the withdrawal API with a Trusted Counterparty as the destination | `Create address` — enables creating a new wallet using the same API key; `Transfer funds` — enables funding sending vaults for settlement via API |
### 2. API key
Create an API key using the permission group above. See [API keys](/knowledge-base/platform/developers/api-keys) for details, including how to generate an Ed25519 key pair.
### 3. Participant vault setup
Set up and configure your participant vault under **Atlas participants** in the web dashboard.
### 4. Wallet balance and transaction information
Before testing settlement APIs, fetch your settlement wallet details to identify balance and `walletId` values required for settlement.
* **List wallets** or **Get wallet by ID** — returns all wallets accessible to the API key, including balance details.
* **List transactions** — returns all on-chain transfers, including outgoing settlement activity and incoming deposits.
### 5. Trusted counterparty IDs
Collect `participantId` values from all counterparties you will be sending to or receiving from. Counterparties must share their participant IDs with you directly.
***
## Quorum or authorization required?
| Settlement | Initiator org | Acceptor org |
| :--------- | :---------------------------------------------------------------- | :-------------------------------- |
| Send | Quorum approval once initiated | Accept only |
| Receive | Quorum approval once initiated | Accept + quorum approval |
| Two-way | Quorum approval once initiated; accept and quorum approve to send | Accept and quorum approve to send |
***
## Settlement workflows
### Conditions for settlement
Before Anchorage Digital holds and moves funds for settlement, the following conditions must be met.
**One-way settlement**
1. The **proposer** has authorized the proposed settlement.
2. The **proposer** has sufficient funds for the settlement amount.
3. The **proposer** has sufficient funds to cover on-chain network fees.
**Two-way settlement**
1. The **proposer** has authorized the proposed settlement.
2. The **proposer** has sufficient funds for the settlement amount.
3. The **proposer** has sufficient funds to cover on-chain network fees.
4. The **acceptor** has accepted and authorized the proposed settlement.
5. The **acceptor** has sufficient funds for the settlement amount.
6. The **acceptor** has sufficient funds to cover on-chain network fees.
### One-way settle (send funds)
1. **(Proposer)** Collect the recipient `participantId` and configure participant vault details.
2. **(Proposer)** Call [Propose a settlement](/knowledge-base/api-reference/endpoints/atlas/propose-settlement). Use negative amounts for assets being sent; positive for assets being received. Amounts exclude fees.
3. **(Proposer)** Call [Authorize settlement](/knowledge-base/api-reference/endpoints/atlas/authorize-settlement) (or authorize via the web dashboard).
4. **(Acceptor)** Poll [List settlements](/knowledge-base/api-reference/v2/atlas-settlement-network/list-settlements) to detect pending settlement actions.
5. **(Acceptor)** Call [Accept settlement](/knowledge-base/api-reference/endpoints/atlas/accept-settlement) (or accept via the web dashboard).
* Select vault and wallet IDs for your side of the settlement.
* Invert the amounts from the List settlements response. The sum of amounts, by asset type, must be exactly opposite the proposer's amounts.
* Use `createWallet` to create a new wallet for an asset if needed.
6. **(Acceptor)** Confirm receipt via **List transactions** (type: `Deposit`).
7. **(Proposer and acceptor)** Verify final state via [List settlements](/knowledge-base/api-reference/v2/atlas-settlement-network/list-settlements).
### One-way settle (receive funds)
1. **(Proposer)** Collect the recipient `participantId` and configure participant vault details.
2. **(Proposer)** Call [Propose a settlement](/knowledge-base/api-reference/endpoints/atlas/propose-settlement). Use positive amounts for assets being received; negative for assets being sent. Amounts exclude fees.
3. **(Proposer)** Call [Authorize settlement](/knowledge-base/api-reference/endpoints/atlas/authorize-settlement) (or authorize via the web dashboard).
4. **(Acceptor)** Collect the recipient `participantId` and configure participant vault details.
5. **(Acceptor)** Poll [List settlements](/knowledge-base/api-reference/v2/atlas-settlement-network/list-settlements) to detect pending settlement actions.
6. **(Acceptor)** Call [Accept settlement](/knowledge-base/api-reference/endpoints/atlas/accept-settlement) (or accept via the web dashboard).
* Select vault and wallet IDs for your side of the settlement.
* Invert the amounts from the List settlements response.
* Use `createWallet` to create a new wallet for an asset if needed.
7. **(Acceptor)** Call [Authorize settlement](/knowledge-base/api-reference/endpoints/atlas/authorize-settlement) (or authorize via the web dashboard). Settlement transfer initiates once all conditions are satisfied.
8. **(Proposer)** Confirm receipt via **List transactions** (type: `Deposit`).
9. **(Proposer and acceptor)** Verify final state via [List settlements](/knowledge-base/api-reference/v2/atlas-settlement-network/list-settlements).
### Two-way settle (send and receive funds)
For a two-way settlement to execute, all four conditions must be met: (1) proposer has authorized, (2) acceptor has accepted, (3) acceptor has authorized, and (4) both parties have fully funded all legs of the settlement, including network fees.
1. **(Proposer)** Collect the recipient `participantId` and configure participant vault details.
2. **(Proposer)** Call [Propose a settlement](/knowledge-base/api-reference/endpoints/atlas/propose-settlement). Use positive amounts for assets being received; negative for assets being sent. Amounts exclude fees.
3. **(Proposer)** Call [Authorize settlement](/knowledge-base/api-reference/endpoints/atlas/authorize-settlement) (or authorize via the web dashboard).
4. **(Acceptor)** Collect the recipient `participantId` and configure participant vault details.
5. **(Acceptor)** Poll [List settlements](/knowledge-base/api-reference/v2/atlas-settlement-network/list-settlements) to detect pending settlement actions.
6. **(Acceptor)** Call [Accept settlement](/knowledge-base/api-reference/endpoints/atlas/accept-settlement) (or accept via the web dashboard).
* Select vault and wallet IDs for your side of the settlement.
* Invert the amounts from the List settlements response.
* Use `createWallet` to create a new wallet for an asset if needed.
7. **(Acceptor)** Call [Authorize settlement](/knowledge-base/api-reference/endpoints/atlas/authorize-settlement) (or authorize via the web dashboard). Settlement transfer initiates once all conditions are satisfied.
8. **(Proposer)** Confirm receipt via **List transactions** (type: `Deposit`).
9. **(Proposer and acceptor)** Verify final state via [List settlements](/knowledge-base/api-reference/v2/atlas-settlement-network/list-settlements).
# Exploring settlement workflows
Source: https://docs.anchorage.com/knowledge-base/platform/developers/atlas/atlas-settlement-explorer
Compare one-way send, one-way receive, and two-way settlement flows across leg scope and instruction channel.
# Exploring settlement workflows
Send, receive, and two-way settlements share the same propose, authorize, and accept mechanics, but differ in who has to authorize and when execution can fire. This explorer walks through the exact sequence for any combination of settlement type, leg scope, and instruction channel.
## The four switches
* **Settlement type**: send (one-way), receive (one-way), or two-way. See [Settlement workflows](/knowledge-base/platform/developers/atlas/atlas-settlement-api#settlement-workflows) for the source procedures.
* **Leg scope**: single-leg or multi-leg, meaning how many asset amounts are bundled into one settlement instruction.
* **Instruction channel**: API or UI, meaning whether authorize and accept happen directly against the endpoints, or in the web dashboard under your organization's quorum policy.
* **Gas source**: gas station or wallet-funded, per [`useGasStation`](/knowledge-base/platform/developers/network-gas-fees#gas-station), meaning whether the on-chain gas for a leg is topped up from the organization's gas station, or paid from the sending wallet's own balance. USD legs never need gas at all; they settle over Fedwire, not a blockchain.
## Reading the diagram
The proposer and acceptor sit on either side of the Atlas settlement network. Wallet chips light up for the asset or assets actually moving in the current step: one chip under single-leg, several under multi-leg. Solid lines are movement of value or an instruction call; dashed lines are polling or verification. The line that animates is the one active in the current step.
The network node's connected-node chain is an illustrative stand-in for settlement state, not a documented enum. Only **Executing** and **Executed** are states the Settlement API integration guide actually names. Every earlier label just names the step most recently completed.
This walkthrough uses the literal USD wallet alongside two illustrative on-chain stablecoins, USDx\_ETH and USDx\_SOL (not Anchorage Digital tickers). USD is fee-exempt and needs no gas, per the integration guide. It settles over Fedwire, not a blockchain. USDx\_ETH and USDx\_SOL are on-chain, so each incurs a network fee and draws gas from either the [gas station](/knowledge-base/platform/developers/network-gas-fees#gas-station) or the sending wallet, depending on the gas source switch: ETH for USDx\_ETH, SOL for USDx\_SOL.
For the authoritative endpoint list, required permissions, and quorum table, see [Settlement API integration guide](/knowledge-base/platform/developers/atlas/atlas-settlement-api).
# B2B2X accounts
Source: https://docs.anchorage.com/knowledge-base/platform/developers/b2b2x
Choose the right account structure for serving your end clients on Anchorage Digital.
You can build product for your end clients on top of Anchorage Digital today. The organization model—vaults and wallets with configurable permissions—gives you the building blocks to segregate, fund, and govern accounts for the clients you serve, without standing up a parallel ledger of your own. This guide explains the structures you can use now and how to pick between them.
## ADx vs. wealth
This page covers business-to-business-to-anything (B2B2X) structures inside a standard **ADx organization**, where you segregate and manage your end clients yourself using vaults and wallets.
The **wealth organization type** is a separate path for retail wealth-specific custody and trading use cases. If that describes your use case, see the [Wealth management overview](/knowledge-base/platform/developers/wealth/wealth-management-overview) instead.
## Key concepts
A few terms used throughout, defined precisely because they're easy to conflate. Both fiat and crypto sit on the same org model—you segregate end clients using vaults and wallets, regardless of asset.
* **FBO account** — a "for benefit of" arrangement where you hold the account relationship, and the funds within it belong to your end clients. You are the account holder of record.
* **End client** — the client of our client. The party you serve in a B2B2X relationship.
* **Vault** — the top-level container in the org model. Carries its own permission set and governance (quorum, approvers).
* **Wallet** — sits inside a vault and holds a single asset. Every wallet maintains a true balance and transaction history. The mapping of a given wallet to a given end client is maintained at the Anchorage Digital Bank (ADB) level.
A vault holds at most one fiat (USD) wallet and any number of crypto wallets. This is why fiat segregation is done at the vault level (one USD wallet each), while crypto can be segregated by adding wallets within a vault.
### Fiat: deposit information is client-specific identity
A fiat deposit is a wire. It needs a name, an address, and routing and account numbers. So the question that drives every fiat structure is whose identity sits on the deposit instructions:
* **Sub-account** — a wallet whose deposit instructions resolve to *your* legal name as the account holder of record. This is what Anchorage Digital supports today. Fiat wallets are sub-accounts with real balances, not pass-through virtual accounts.
* **Named account** — a sub-account whose deposit instructions bear the *end client's* name rather than yours, so the end client can receive wires addressed to them directly. In development.
* **True virtual account** — a pure pass-through set of deposit instructions in the end client's name, where Anchorage Digital doesn't track the end client's balance. Not available.
Today, fiat deposit instructions resolve to your name, not the end client's. The end-client-to-wallet mapping is maintained at the ADB level, and isn't surfaced as a distinct named account at the bank.
### Crypto: the wallet address carries no identity
A crypto deposit is just a wallet address that follows the chain's standard. There's no name, address, or bank identity attached to it. That means:
* There's no client-specific deposit instruction to name. The address can stay obscured to the end client without losing anything, because it conforms to crypto standards rather than carrying identity.
* There's no crypto FBO or named-account concept, because there's nothing on the address to name. Segregation is handled entirely by which wallet maps to which end client at the ADB level.
So the sub-account, named account, and true virtual account distinctions are a fiat story. For crypto, segregation is simply wallet-to-client mapping, and it works today.
## Structures available today
| Structure | What it is | Who it's for | Availability |
| :----------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------- | :--------------------- |
| **Segregated vaults and wallets per end client** | You create a dedicated vault and wallet for each end client. Each end client is KYC'd by Anchorage Digital. Funds are segregated natively through the org model, and balances are real per wallet. | Most B2B2X clients. The default, recommended path. | Available |
| **Omnibus plus your own sub-ledger (reliance)** | You hold pooled funds in a single account and maintain per-end-client balances on your own systems, with flexibility on how you use the native vaults and wallets. | Clients approved by Anchorage Digital for a KYC reliance arrangement who run their own sub-ledger. | Available, by approval |
In the **segregated** model, each end client's funds sit in their own vault and Anchorage Digital keeps them separated for you. In the **omnibus** model, funds are commingled in shared wallets and you decide how to use the native vaults and wallets, tracking each end client's balance in your own sub-ledger. Segregated is the default; omnibus is available by approval.
Today, vaults are created in the web dashboard (not via API), and a vault holds a single USD wallet. The patterns below reflect those constraints.
### Segregated vaults and wallets per end client
This is the structure most B2B2X clients use today, and the one we recommend. Each end client gets their own vault and wallet, so balances are segregated natively by the org model. You don't build or maintain a ledger on top.
Every account sits under your FBO relationship and is held in your legal name. Each end client is segregated into their own vault, with wallets per asset underneath, and deposits and withdrawals flow between the end client and their wallet.
**How it works**
* You submit a KYC package for the end client to Anchorage Digital's compliance team.
* Once compliance approves, you create a vault in that end client's name with a dedicated wallet, used exclusively for that client.
* The wallet holds a real balance. The end-client-to-vault association is tracked at the ADB level.
* Deposit instructions on the wallet resolve to your legal name as the account holder of record.
**Recommended setup pattern**
Because compliance approval is the gating step and vaults today hold a single USD wallet, the cleanest pattern is to pre-provision vault shells:
1. In the web dashboard, create vaults in advance as empty shells: unfunded, unnamed, and not exposed to the end client.
2. Pre-assign each vault the permission set you want to govern it (quorum, approvers).
3. Upon KYC approval, name the vault to the end client and put it into use. Create the vault's USD wallet with `POST /v2/vaults/{vaultId}/wallets` if it doesn't already exist—it's also created automatically the first time the vault receives an internal deposit. Add any crypto wallets with the same endpoint.
This keeps you ready to onboard quickly while ensuring no end client can access or transact in an account before compliance has cleared it. **Named accounts** are in development: today the wallet's deposit instructions carry your name, not the end client's. Named accounts will let a wallet bear the end client's own name and instructions, so end clients can receive wires addressed to them directly.
#### Step 1: Confirm or create the wallet
Wallet provisioning differs by asset:
* **USD** — a vault doesn't get a USD wallet automatically when it's created. Create one with `POST /v2/vaults/{vaultId}/wallets`, or it's created automatically the first time the vault receives an internal deposit. Fetch it with `GET /v2/wallets/{walletId}` to read its wire instructions.
* **Crypto** — create a wallet per asset in the end client's vault. Use `POST /v2/vaults/{vaultId}/wallets` with the `assetTypeID` set to the asset ticker (for example `BTC`, `ETH`), then fetch it to read its deposit address.
```json theme={null}
{
"assetTypeID": "BTC",
"name": "End Client A BTC"
}
```
Provide each end client a deposit wallet per asset within their associated vault.
#### Step 2: Fund the wallet
There's no "create deposit" call. You share the wallet's deposit details with the end client and monitor for the incoming deposit. In both cases you can monitor with [webhooks](/knowledge-base/platform/developers/webhooks/webhooks-overview) or by polling `GET /v2/transactions`.
**Fiat (USD wire)**
Fetch the wallet to read its wire instructions, then share them with the end client. When the wire arrives, it carries a `fiatDetails` object you use to tie out the deposit:
```json theme={null}
"fiatDetails": {
"accountNumber": "123456789",
"bankId": "987654321",
"bankName": "Anchorage Digital Bank",
"fedWire": "WIRE12345",
"memo": "Q1 Payout",
"name": "Jane Doe"
}
```
The `name` and bank fields let you match the incoming wire to the sending end client. No deposit attribution step is required for fiat wires. You can also have the depositor set a known `memo` to make matching unambiguous.
**Crypto**
Fetch the wallet to read its deposit address, share the address with the end client, and monitor with [webhooks](/knowledge-base/platform/developers/webhooks/webhooks-overview). The address follows the chain standard and carries no client identity, so it can stay opaque to the end client.
A crypto deposit from a non-whitelisted address lands pending and is excluded from `availableBalance` until you attribute it. Attribute it on the web platform or with `PATCH /v2/deposit-attributions`. If the end client will deposit from the same address again, add it as a trusted source.
#### Step 3: Withdraw
Withdrawals use one endpoint for both fiat and crypto. The `assetTypeID` and `destination` set the type. The destination must be a Trusted Destination that has been created and quorum-approved before you call this.
`POST /v2/transactions/withdrawal`
```json theme={null}
{
"assetTypeID": "USD_R",
"source": {
"type": "WALLET",
"id": "24bd12752fcbaec0100d20fa6c3b1a06"
},
"destination": {
"type": "STANDING_INSTRUCTION",
"id": "9f1c2b7a-2f7e-4a3f-9a5d-0c1a2b3d4e5f"
},
"amount": {
"amount": "250000.00",
"currency": "USD"
},
"clientReferenceId": "withdrawal-2025-10-31-0001",
"note": "Treasury rebalance"
}
```
Where:
* `assetTypeID` — `USD_R` in staging and `USD` in production for fiat, or the asset ticker for crypto.
* `source` — the end client's wallet (`type: WALLET`, `id`: the wallet ID).
* `destination` — the approved Trusted Destination. Fiat withdrawals use a standing instruction (`STANDING_INSTRUCTION`); both fiat and crypto can target a `TRUSTED_DESTINATION`.
* `clientReferenceId` — your idempotency and reconciliation key.
For crypto, set `assetTypeID` to the asset ticker and point `destination` at the approved crypto Trusted Destination. Monitor status with `GET /v2/transactions`, `GET /v2/transfers`, or webhooks. To move funds between two wallets inside your organization rather than out to a Trusted Destination, use a transfer with `destination.type: WALLET`.
### Omnibus plus your own sub-ledger (reliance)
If you're approved for a **KYC reliance arrangement**, you can hold pooled funds in a single account and run your own sub-ledger to track each end client's balance. Two conditions apply:
1. **Reliance approval.** Anchorage Digital's compliance team must approve a reliance arrangement with you, relying on your KYC program for your end clients rather than KYC'ing each one directly. This is granted case by case and isn't available to every client.
2. **You maintain the sub-ledger.** Anchorage Digital tracks the pooled balance. Per-end-client balances are yours to maintain. Building and operating that sub-ledger is non-trivial work that sits on your side.
Under reliance, deposits arrive into your account in your name, and Anchorage Digital doesn't see which end client each deposit belongs to. That attribution lives in your sub-ledger. If you need to distinguish incoming funds, direct end clients to include an identifying memo on the wire.
Most clients who want native per-end-client identification without running their own sub-ledger are better served by segregated vaults and wallets today, or by named accounts once available.
## What's coming
These are in scope or in build, and aren't available today. They're listed so you can plan, without committing to dates:
* **Named accounts** — sub-accounts that carry the end client's own name and deposit instructions, so end clients receive wires addressed directly to them while funds still settle within your account. In active build.
* **True virtual accounts (native pass-through)** — pass-through deposit instructions in the end client's name where Anchorage Digital doesn't maintain the end client's balance, with native sub-ledgering on Anchorage Digital's side. A known future need, not currently being built. Clients who require native sub-ledgering at retail scale today typically use a third-party ledger provider.
If a true virtual account or native sub-ledger is a hard requirement for your build, talk to your Anchorage Digital contact so we can factor it into prioritization.
## Choosing your structure
* **You want Anchorage Digital to segregate and KYC each end client, with real per-client balances:** segregated vaults and wallets. Recommended for most clients.
* **You're a large, sophisticated platform that wants one account and will run your own sub-ledger, and you can qualify for reliance:** omnibus plus reliance.
* **You need end clients to receive wires in their own name:** named accounts, once available. Use segregated vaults and wallets in the meantime.
* **You're a retail-scale wealth platform onboarding end clients under reliance:** see the [Wealth management overview](/knowledge-base/platform/developers/wealth/wealth-management-overview).
# Bitcoin address types
Source: https://docs.anchorage.com/knowledge-base/platform/developers/bitcoin-address-types
Choose between wrapped SegWit and Taproot wallet addresses and understand how external address formats are handled.
Anchorage Digital supports two Bitcoin address types for client wallets: wrapped SegWit and Taproot. This page covers what each type is for and how addresses in other formats are handled.
## Wallet address types
| Address type | Starts with | Availability |
| :--------------------------- | :---------- | :------------------------------------------------------------------ |
| Wrapped SegWit (P2SH-P2WPKH) | `3` | Default for every new Bitcoin wallet |
| Taproot (P2TR) | `bc1p` | Optional—select the address type **Taproot** when creating a wallet |
Wrapped SegWit uses SegWit's smaller transaction size while remaining compatible with older wallet software. Taproot wallets are required to [stake Bitcoin with Babylon](/knowledge-base/platform/users/staking/babylon-btc).
Anchorage Digital doesn't generate legacy (P2PKH) or native SegWit (bech32) addresses for client wallets.
Taproot wallet creation isn't available on Porto.
## Transacting with other address formats
Your wallet's address type doesn't limit who you can transact with:
* **Deposits**—any external wallet can send to your Anchorage Digital deposit address, regardless of the sender's own address format.
* **Withdrawals**—you can withdraw to any standard Bitcoin address format, including legacy (P2PKH), P2SH, native SegWit (bech32), and Taproot (bech32m).
Always [verify a deposit address](/knowledge-base/api-reference/address-verification) before sharing it.
# Overview
Source: https://docs.anchorage.com/knowledge-base/platform/developers/etf/etf-overview
Key terminology, architecture, and APIs for the Anchorage Digital ETF integration.
This guide covers the core concepts for integrating an ETF program with Anchorage Digital: the roles involved, how the ledger keeps fund assets separate from operating costs, vault design options, and how to automate operations with the API.
## Roles in an ETF program
Owns the fund and its mandate. Approves onboarding and the custody relationship, and decides which liquidity providers and settlement partners can participate.
An optional subadvisor or settlement partner that tokenizes the fund's holdings and directs creation and redemption on-chain, if the issuer delegates this role.
The qualified custodian. Custodies fund assets, configures trusted destinations, and provides the API and reporting the other parties rely on.
Authorized participants that deliver and receive assets against the fund to perform creation and redemption arbitrage. Most programs work with four to five liquidity providers.
Maintains the investor register and net asset value (NAV), and whitelists investor-facing wallets as trusted destinations.
## How the ledger works
From your side of the integration, an ETF program looks like a standard Anchorage Digital vault and wallet setup — the same building blocks covered in [Account hierarchy](/knowledge-base/platform/developers/account-hierarchy) and [B2B2X accounts](/knowledge-base/platform/developers/b2b2x). You don't create or manage anything through the Subaccounts API the way the [wealth management integration](/knowledge-base/platform/developers/wealth/wealth-management-overview) does.
Internally, Anchorage Digital's ledger still splits each ETF vault's holdings into three balances, visible on the web dashboard's Balances tab:
| Balance | What it tracks |
| :------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Fund balance | The grantor trust's actual custodied assets. This is what the fund's NAV is based on. |
| Network fee balance | Assets set aside to pay on-chain network fees (sometimes called gas), kept separate so spending on fees never affects the fund's NAV or creates an unexpected taxable event. |
| Unattributed balance | Dust or unattributed deposits, excluded from both balances above. |
Anchorage Digital funds one network fee balance per organization, not per wallet, so you don't need a wallet-specific top-up before using a new wallet. If you need to withdraw an exact amount without drawing on the shared network fee balance, contact your account representative to fund that specific wallet directly.
## Vault topology
How you structure vaults across your liquidity providers is a trade-off between segregation and operational simplicity.
| Model | How it works | Trade-off |
| :------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Dedicated vault per liquidity provider | Each liquidity provider gets its own vault or wallet, visible only to them. | Maximum segregation and per-counterparty control, at the cost of managing more vaults as you add liquidity providers. |
| Shared settlement vault | All liquidity providers settle into one working vault, identified only by their registered trusted-source address. A separate reserve vault holds core fund assets off the settlement path. | Simpler to operate, but relies on every liquidity provider using a unique, non-reused trusted-source address — a shared or reused address breaks attribution between counterparties. |
You can combine either vault model with API-driven operations below.
## Automating operations with the API
Rather than Anchorage Digital manually adding and removing individual users for an operating partner, you can issue that partner a single [API key](/knowledge-base/platform/developers/api-keys) and let them manage their own users under it. This removes Anchorage Digital from routine access requests and lets the partner move as fast as their own approval process allows.
Pair this with [webhooks](/knowledge-base/platform/developers/webhooks/webhooks-overview) instead of polling for status — subscribe to deposit, settlement, and report-ready events to drive same-day, event-based reconciliation instead of manual checks. See [Trusted destinations](/knowledge-base/platform/developers/move-money/setup/trusted-destinations), [Deposits](/knowledge-base/platform/developers/move-money/deposit), and [Withdrawing crypto](/knowledge-base/platform/developers/move-money/withdraw/crypto) for the underlying transfer APIs.
## Reporting
Anchorage Digital sends the transfer agent (or fund administrator) two automated reports each day: account balances and the prior day's transactions, delivered by email or SFTP. Monthly custody statements cover the fund balance only — network fee and unattributed balances are excluded.
Each ETF asset type is set up as its own organization. An issuer with both a BTC ETF and an ETH ETF has two separate organizations, one per fund.
# FAQs
Source: https://docs.anchorage.com/knowledge-base/platform/developers/faqs
Frequently asked questions about the Anchorage Digital API, sandbox, devices, and account management.
Find answers grouped by topic — transfers, quorum, onboarding, devices, API access, sandbox, and network fees.
## Transfers and withdrawals
Withdrawals require quorum approval; transfers do not. Transfers are also more configurable — specifically in how network fees are charged — and allow you to queue multiple transfers from the same wallet simultaneously, assuming sufficient funds.
See the [Transfers vs. withdrawals](/knowledge-base/platform/developers/move-money/transfers-vs-withdrawals) guide and the Transactions section of the API reference for more information.
All external withdrawal requests made via API and the iOS app go through quorum approval and Anchorage Digital risk review. You can add "trusted destinations" and notify your client experience manager to ensure all transfers to non-approved destinations are rejected.
## USD and banking
No. Anchorage Digital's USD wallets aren't assigned an IBAN (International Bank Account Number)—the account-numbering standard used mainly in Europe and other SEPA-participating countries.
Instead, your USD wallet's wire instructions include a US bank account and routing number for domestic wires, and a SWIFT/BIC code for international wires. A SWIFT/BIC (Bank Identifier Code) identifies a specific bank rather than an individual account, and routes an international wire to the correct bank. Share your wallet's SWIFT/BIC with senders wiring funds from outside the United States.
No. A vault doesn't get a USD wallet by default. A USD wallet is created either:
* Via the **Deposit** flow in the iOS app or web dashboard, or the `POST /v2/vaults/{vaultId}/wallets` API call, before you deposit funds, or
* Automatically, the first time the vault receives an internal deposit from another vault on the platform.
See [USD banking](/knowledge-base/platform/users/usd-banking#creating-a-usd-wallet) for the dashboard flow, or [Deposit](/knowledge-base/platform/developers/move-money/deposit#create-a-wallet-and-address) for the API.
## Quorum and approvals
A quorum authenticates organizational intent — ensuring that initiated transactions align with your organization's governing structure. Quorums are required both internally at Anchorage Digital and for client operations.
New clients must onboard a minimum of three admins. All initial users are admins. From there, new users, vaults, and policies are established through an admin quorum.
Yes. All transactions require a valid quorum of unique, unforgeable cryptographic signatures from multiple organization members. Quorums are configurable per vault as any M-of-N.
For example, a company with five employees authorized to transfer funds might require three of five approvals per transaction. You can also specify a required user for any quorum and use different quorum settings per vault within an account.
## Onboarding and user management
To complete sandbox onboarding, you must complete the KYC form sent to you. If you entered sensitive information you'd like redacted, contact [accountexecutive@anchorage.com](mailto:accountexecutive@anchorage.com).
In production, all onboarded users undergo full KYC to access the Anchorage Digital iOS app and web dashboard.
Anchorage Digital reviews and approves onboarding video submissions. If your account has not been approved within an hour, contact your Anchorage Digital point of contact via email or Slack.
To gain access to the TestFlight app, the new member should contact your main Anchorage Digital point of contact. Once the app is installed, an admin must generate a QR code:
**Admin steps:**
1. Tap the gear icon ⚙️ at the lower right of the app, then tap **Users**.
2. Tap the add icon ➕ at the top right.
3. Follow the prompts to set policies and vaults.
4. Share the unique QR code with the new user (screenshot and email if not in the same location).
**New user steps:**
1. Scan the QR code in the Anchorage Digital iOS app.
2. Input preliminary KYC information including basic personal data, voice, and biometric training.
3. Wait for quorum approval.
The initiating admin will be prompted for biometric approval. A second approver is then required. Finally, Anchorage Digital compliance reviews the new user's PII and completes due diligence before approving.
## Devices and security
Anchorage Digital supports iOS devices only — iPhones and iPads — due to the secure enclave within these devices. Without an iPhone, you cannot access the sandbox app, web dashboard, or member quorum. You can still call the APIs using keys created and shared during onboarding.
Device security is critical for safeguarding accounts and signing on-chain transactions. If other devices release similar functionality, Anchorage Digital will re-evaluate support at that time.
**Supported iOS devices:**
* iPhone 8, 8 Plus, X, XS, XS Max, XR, 11, 11 Pro, 11 Pro Max, SE (2nd gen), 12, 12 Pro, 12 mini, 13, 13 Pro, 13 mini
* iPad (5th gen and later), mini 4, mini (5th and 6th gen), Air 2, Air (3rd and 4th gen), Pro (all versions)
You can start this yourself, there's no need to contact Anchorage Digital or have the device marked as lost. On your old device, go to **Settings** and tap **Replace my device** to generate a QR code. Install the app on the new phone, scan the QR code, and confirm with biometrics on your old device. Quorum administrators then approve the operation, and Anchorage Digital reviews it for final approval. See [Device and login recovery](/knowledge-base/platform/users/device-login-recovery#replacing-an-iphone-with-access-to-your-old-device) for the full steps.
Inform Anchorage Digital immediately at [accountexecutive@anchorage.com](mailto:accountexecutive@anchorage.com). The device will be marked as "lost" and deactivated. When you get a new device, an administrator with user management permissions initiates a device replacement to restore your access. See [Device and login recovery](/knowledge-base/platform/users/device-login-recovery#replacing-an-iphone-without-access-to-your-old-device) for the steps.
This flow is only for devices that are gone. If you still have your old device, use the replace-device flow above instead. See [Device and login recovery](/knowledge-base/platform/users/device-login-recovery#replacing-an-iphone-with-access-to-your-old-device).
## API access and authentication
| Environment | URL |
| ----------- | ----------------------------------- |
| Production | `https://api.anchorage.com` |
| Sandbox | `https://api.anchorage-staging.com` |
If your network restricts inbound traffic, allowlist the IP addresses Anchorage Digital sends requests from — for example, webhook deliveries to your endpoints. Allowlist the full set for the environment you integrate with, as requests can originate from any of these addresses.
| Environment | IP addresses |
| ----------- | ---------------------------------------------------- |
| Sandbox | `35.199.162.229`, `34.187.238.97`, `136.109.216.145` |
| Production | `34.182.59.208`, `34.83.146.129`, `35.203.149.37` |
See the [Request signing](/knowledge-base/platform/developers/request-signing) page for full instructions and reference client scripts.
The default is to require a signature; read-only endpoints are the exception. Signatures are optional unless explicitly required but are encouraged for all requests — if provided, they will be verified.
Endpoints that require signing will specify the `Api-Signature` and `Api-Timestamp` headers as additional parameters and require an Ed25519 signature alongside the API key.
Yes. Revoke a key via the web dashboard or by emailing [accountexecutive@anchorage.com](mailto:accountexecutive@anchorage.com).
Revoked keys cannot be reinstated. A new key must be created. You do not need quorum approval or risk review to create a new key using an existing permission group.
To revoke: go to the **API** section of the web dashboard, select the three-dot icon next to the key, and select **Revoke**.
Only admin users with the correct access credentials can revoke API keys. Any user (admin, member, view-only) can view permission group details and past keys, but no user can see the actual hexadecimal key value.
## Sandbox
Yes. Sandbox assets run on their own testnets. For example, sandbox uses `BTC_T` (testnet) while production uses `BTC` (mainnet).
## Network and gas fees
The wallet must hold sufficient balance to cover transaction fees — an estimated balance for withdrawals, staking, and smart contract operations, and a fixed fee threshold for API-initiated transfers.
Gas fees are calculated by multiplying the gas limit (maximum gas willing to spend) by the gas price (ETH per gas unit). They are paid in ETH and used to protect the network and incentivize validators.
As of January 24, 2024, the threshold for ETH is set to 0 ETH unless the gas station is used. Actual fees vary by network conditions at broadcast time. When using the gas station, no minimum ETH balance is required.
The wallet must hold an ETH balance calculated from gas limit estimates, multipliers for gas limit and price, and priority fees — unless the transfer uses the Gas Station, which requires no ETH balance.
Anchorage Digital sets a MaxFee to ensure users don't overpay while still having enough for transaction processing. Priority fee is set to 0.01 Gwei.
For ERC-20 withdrawals and transfers, avoiding dust is not possible due to the non-deterministic nature of gas for smart contract interactions. For ETH transfers, it is theoretically possible to avoid dust by specifying maxFee and maxPriorityFee to consume the remaining balance, but this is not currently supported on the platform.
# Deposit
Source: https://docs.anchorage.com/knowledge-base/platform/developers/move-money/deposit
Receive digital assets and USD into Anchorage Digital wallets and vaults.
A **deposit** is how funds enter Anchorage Digital. Receiving funds never requires quorum approval and never incurs a fee for the receiver. To accept funds, you create a place for them to land—a wallet and deposit address for digital assets, or a USD account for fiat—then share those details with the sender and watch for arrival.
## No quorum, no fee
Deposits are inbound, so there's no per-transaction quorum and no receiver-side network fee. The controls that matter for deposits are identity (attributing unknown senders) and address integrity (verifying the address you share is genuinely yours).
## Deposit guides
Create a wallet and deposit address to receive digital assets, then track and attribute the deposit.
Receive USD by wire and reconcile inbound funds.
## Create a wallet and address
A wallet lives inside a vault and is created for a specific asset network. Create one with the **Deposit** button in the web or iOS dashboard, or via API.
```json theme={null}
// POST /v2/vaults/{vaultId}/wallets
{
"networkId": "{asset network ID}",
"walletName": "Bitcoin Mainnet - Wallet 1"
}
```
A vault doesn't get a USD wallet automatically when it's created. Create one with this same endpoint before depositing, or Anchorage Digital creates one automatically the first time the vault receives an internal deposit from another vault on the platform.
Provision a deposit address for an existing wallet:
```bash theme={null}
curl --request POST \
--url https://api.anchorage-staging.com/v2/wallets/{walletId}/addresses \
--header 'Api-Access-Key: {API key}' \
--header 'accept: application/json'
```
Creating addresses requires the `Create address` permission. Reading wallets and addresses requires `Read vault activity`.
## Monitor arrivals
Subscribe to webhooks to be notified when funds land. See [Webhooks](/knowledge-base/platform/developers/webhooks/webhooks-overview). For digital assets, delivery waits on on-chain confirmation, typically around two confirmations depending on the blockchain; USD deposits notify once the wire settles.
## Deposit APIs
| API | Description |
| :-------------------------- | :--------------------------------------------------------- |
| Create a wallet in a vault | Creates a wallet for an asset network to receive deposits. |
| Provision a deposit address | Generates a new deposit address for a wallet. |
| List addresses for an asset | Returns existing deposit addresses for an asset. |
| List deposit attributions | Returns deposits pending or completed attribution. |
# Crypto deposit
Source: https://docs.anchorage.com/knowledge-base/platform/developers/move-money/deposit/crypto
Receive digital assets end to end: create and verify a wallet address, track the deposit, and attribute the sender.
Receiving a digital asset is a single end-to-end flow: create a wallet and deposit address, verify and share it, then track the incoming deposit and—when it arrives from an unrecognized sender—attribute it before the funds become available. This page walks the full path. For the shared wallet and address mechanics, see [Deposit](/knowledge-base/platform/developers/move-money/deposit).
Two endpoints describe the same deposit from different angles, and you use both once funds are inbound:
* **`GET /v2/transactions`** — the money view: how much arrived, in what asset, from which address, and its on-chain status.
* **`GET /v2/deposit-attributions/attributions`** — the compliance view: whether the deposit is held or cleared, and who sent it.
They link on the transaction `id`, which is the `depositTransactionId` in the attributions response, and both carry the same `blockchainTxId`.
## Deposit flow
Call `POST /v2/vaults/{vaultId}/wallets`, passing the `networkId` and a `walletName`.
Call `POST /v2/wallets/{walletId}/addresses`, or list existing addresses with `GET` on the addresses endpoint.
Anchorage Digital signs every deposit address so you can confirm it was generated for your organization and hasn't been tampered with. Confirm both that the signature is valid and that the signed address matches the one you intend to share. See [Address verification](/knowledge-base/api-reference/address-verification).
Share the verified address with the sender, who sends only the correct asset on the correct network. If you expect recurring deposits from this sender, add their address as a **trusted source** so future deposits attribute automatically and skip the manual step below.
Subscribe to webhooks to be notified on arrival. A deposit from an unrecognized sender fires `deposit.pending-attribution` with the `transactionId`. Read the deposit with `GET /v2/transactions`: it shows `status: SUCCESS` on-chain, but the funds are excluded from `availableBalance` until attribution completes.
```json theme={null}
{
"data": [
{
"id": "0e2b2f9d8d104f1e960b28567255045f",
"transactionType": "DEPOSIT",
"status": "SUCCESS",
"assetType": "ETH",
"amount": {
"quantity": "5.0",
"assetType": "ETH",
"currentPrice": "3450.12",
"currentUSDValue": "17250.60"
},
"blockchainTxId": "0x84ddb76708d570101db89fd27b1717484c54417c9f32c63052cdfac9a0bfc0a2",
"sourceAddresses": ["0xb4Bb4E3D7f35ede58d99F5e2b8B04f7AC87f9c88"],
"destinationAddresses": ["0x39d9f4640b98189540A9c0Ede2b8B04f7AC8aa21"],
"dateTime": "2026-06-24T14:08:31.000Z",
"vaultId": "1c920f4241b78a1d483a29f3c24b6c4c",
"vaultName": "End Client A",
"walletId": "d24b424293c0d64c6194f52801b3d293"
}
],
"page": { "next": null }
}
```
The same deposit appears under `GET /v2/deposit-attributions/attributions` with `status: PENDING` and empty originator fields—this is what you complete. No amount or value is returned here. A deposit from a **trusted source** is already `ATTRIBUTED` at this point, so you can skip the next step.
```json theme={null}
{
"data": [
{
"depositTransactionId": "0e2b2f9d8d104f1e960b28567255045f",
"blockchainTxId": "0x84ddb76708d570101db89fd27b1717484c54417c9f32c63052cdfac9a0bfc0a2",
"assetType": "ETH",
"status": "PENDING",
"attributionType": null,
"originatorName": null,
"originatorCountry": null,
"sourceWalletType": null,
"sourceAddresses": ["0xb4Bb4E3D7f35ede58d99F5e2b8B04f7AC87f9c88"],
"subaccountId": "ec761b5e-fd2c-497a-a9a0-f8738ac97bdf",
"createdAt": "2026-06-24T14:08:45.953571Z",
"attributedAt": null
}
],
"page": { "next": null }
}
```
Identify who sent the funds. Attribution via API requires the `Deposit Attribution` permission.
```json theme={null}
// POST /v2/deposit-attributions/{depositTransactionId}
{
"notes": "Q2 funding",
"originatorCountry": "US",
"originatorName": "Acme Holdings",
"sourceWalletType": "SELF_HOSTED"
}
```
The record moves to `status: ATTRIBUTED`, and the funds are released into `availableBalance`. A `deposit.attributed` webhook fires to confirm.
Poll `GET /v2/transactions` to reconcile the money and `GET /v2/deposit-attributions/attributions` to clear the hold. A deposit can be `SUCCESS` on-chain while still `PENDING` for KYT.
## Trusted sources and automatic attribution
Not every deposit needs the manual attribution step. Attribution is applied automatically when:
* **Trusted sources** — Any address you add as a trusted source is attributed automatically on future deposits. Create them in the dashboard (not currently available via API). They're recommended for senders you receive from repeatedly, and turn the flow above into a track-only path.
* **Travel rule** — Crypto deposits from VASPs above the \$2,100 travel-rule reporting threshold are attributed automatically when Anchorage Digital receives a travel-rule message from a participating VASP. This isn't instant; use the API if you need faster access to funds.
* Everything else needs manual attribution.
### Field guidance
* **`originatorName`** and **`originatorCountry`** — The actual person or entity that sent the funds, not the financial institution.
* **`sourceWalletType`** — `CUSTODIAL` when the sender doesn't hold the private key (a third party does, for example an exchange or custodian), or `SELF_HOSTED` when the sender holds the private key (for example, a self-custody wallet).
Deposits identified as spam or dusting can be attributed as spam through the spam endpoint, which keeps unwanted balances out of statements and trading balances.
### Attribution status values
| `status` | Description |
| :----------------- | :------------------------------------------------------------------------------------------------------------------------------------ |
| `INITIATED` | Deposit detected; Anchorage Digital is attempting automatic spam attribution. Moves to `PENDING` if that fails. |
| `PENDING` | Deposit landed after the auto-attribution attempt and needs attribution. Deposits marked spam by Anchorage Digital don't appear here. |
| `UNDER_REVIEW` | Attribution completed but triggered a sanctions hit pending compliance clearance. |
| `ATTRIBUTED` | Terminal success state; funds are available. |
| `BLOCKED` | Confirmed sanctions hit. |
| `NON_ATTRIBUTABLE` | Semi-terminal state for specific edge cases. |
### Attribution type values
| `attributionType` | Description |
| :---------------- | :--------------------------------------------------------------------------------- |
| `AUTOMATIC` | Attributed automatically via travel-rule information from the originating VASP. |
| `TRUSTED_SOURCES` | Attributed automatically using stored information for a designated trusted source. |
| `MANUAL_STAFF` | Attributed by Anchorage Digital staff from previously known source information. |
| `MANUAL_CLIENT` | Attributed by the client via the web dashboard. |
| `CLIENT_API` | Attributed by the client via API key. |
| `SPAM` | Attributed as spam by Anchorage Digital or the client. |
## Address integrity
Always verify a deposit address before use. The addresses API returns a signature and metadata that prove the address belongs to your vault and network. See [Address verification](/knowledge-base/api-reference/address-verification) for the V1 and V2 schemes.
## Failed and unrecognized deposits
Sending the wrong asset type to an Anchorage Digital address results in a failed deposit. An asset sent on a different chain than the address is not recognized. If the address is correct but the asset is unsupported—for example, an unsupported ERC-20 sent to an ETH address—contact your client experience team.
# USD deposit
Source: https://docs.anchorage.com/knowledge-base/platform/developers/move-money/deposit/usd
Receive US Dollars by wire and reconcile inbound funds from the transaction's fiat details.
USD enters Anchorage Digital by wire into the bank account associated with your USD wallet. Deposits settle without quorum and carry no receiver-side fee. For the shared model, see [Deposit](/knowledge-base/platform/developers/move-money/deposit).
Unlike crypto, a cash deposit doesn't go through deposit attribution. The sender's bank details arrive on the transaction itself, so you reconcile inbound funds directly from `GET /v2/transactions`.
## USD deposit rails
Wire transfers
ACH—reach out to your relationship manager for beta access
RTP and FedNow
Don't have senders push ACH deposits to your USD wallet's account details—only wire transfers are accepted.
## Receive and reconcile USD
A vault doesn't get a USD wallet automatically when it's created. If it doesn't have one yet, create it with `POST /v2/vaults/{vaultId}/wallets`—see [Create a wallet and address](/knowledge-base/platform/developers/move-money/deposit#create-a-wallet-and-address). Anchorage Digital also creates one automatically the first time the vault receives an internal deposit.
Retrieve the bank wire details for your USD account from the web dashboard, and share them with the sender.
The sender initiates a wire to those details. Once the funds settle, a `deposit.attributed` webhook fires with the `transactionId`. USD deposits don't require attribution, so `deposit.pending-attribution` never fires for fiat. See [Webhooks](/knowledge-base/platform/developers/webhooks/webhooks-overview).
Fetch the transaction to reconcile the funds against your ledger. The `fiatDetails` object carries the sender's name, bank, and memo—no attribution step is required.
```json theme={null}
{
"data": [
{
"id": "c37f304cc2b4daf2e5db4b1370288fee",
"transactionType": "DEPOSIT",
"status": "SUCCESS",
"assetType": "USD_R",
"amount": {
"assetType": "USD_R",
"quantity": "250000.00",
"currentPrice": "1",
"currentUSDValue": "250000.00"
},
"fiatDetails": {
"name": "Acme Holdings",
"accountNumber": "987654321",
"bankId": "021000021",
"bankName": "Example Bank",
"fedWire": "20260603MMQFMP6N012345",
"memo": "Q2 funding"
},
"dateTime": "2026-06-03T20:40:43.299Z",
"description": "Inbound wire",
"sourceAddresses": [],
"destinationAddresses": [""],
"vaultId": "c6b0292e409963141824694e44a37e09",
"vaultName": "End Client A",
"walletId": "f947e1645384deb79d2f3e7260e4f1c0"
}
],
"page": { "next": "/v2/transactions?afterId=c37f304cc2b4daf2e5db4b1370288fee&limit=1&types=DEPOSIT" }
}
```
### Reconcile from `fiatDetails`
| Field | Use |
| :---------------------- | :-------------------------------------------------------------------------------------------------- |
| `name` | Sender's name as it appears on the wire—match against the expected end client. |
| `bankName` and `bankId` | Originating bank and its identifier. |
| `accountNumber` | Sender's account number. |
| `fedWire` | The wire reference for the transaction. |
| `memo` | Any memo or OBI the sender included—have senders include a known memo to make matching unambiguous. |
For more on USD accounts, see the USD banking user guide.
# Operate
Source: https://docs.anchorage.com/knowledge-base/platform/developers/move-money/operate
Monitor movement status and understand network fees once assets are in motion.
Once money is moving, two things matter day to day: knowing the status of each movement, and understanding the network fees attached to it.
Follow transfers, withdrawals, and deposits to completion.
How blockchain fees work and how the gas station handles them.
# Track movement status
Source: https://docs.anchorage.com/knowledge-base/platform/developers/move-money/operate/track-status
Follow transfers, withdrawals, and deposits to completion using polling or webhooks.
Every movement can be followed two ways: poll the read APIs, or subscribe to webhooks for event-driven updates.
## Read APIs
| Movement | Poll |
| :--------- | :--------------------------------------------------------------------------- |
| Transfer | `GET /v2/transfers`, or `GET /v2/transfers/{transferId}` |
| Withdrawal | `GET /v2/transactions`, or `GET /v2/transactions/{id}` |
| Deposit | `GET /v2/transactions`, or list deposit attributions for pending attribution |
Transfers and withdrawals use different status vocabularies. Transfers move through `QUEUED`, `IN_PROGRESS`, `COMPLETED`, and `FAILED`. Withdrawals move through `NEEDS APPROVAL`, `INPROGRESS`, `SUCCESS`, `FAILURE`, `REJECTED`, and `EXPIRED`. See [Transfer](/knowledge-base/platform/developers/move-money/transfer) and [Withdraw](/knowledge-base/platform/developers/move-money/withdraw) for the full lifecycles.
## Webhooks
Subscribe to webhooks to receive updates as operations and transactions change state, instead of polling. For digital assets, delivery waits on on-chain confirmation, typically around two confirmations; USD events fire once the transfer or wire settles. See [Webhooks](/knowledge-base/platform/developers/webhooks/webhooks-overview).
### Correlate a webhook to its transaction
Webhook events are lightweight—each carries the identifier of the affected record, not its full detail. On receipt, fetch the record and inspect it:
A `deposit.*`, `transfer.*`, or `withdrawal.*` event arrives with the transaction identifier. See [Webhooks](/knowledge-base/platform/developers/webhooks/webhooks-overview) for the event catalog and payload fields.
Look it up with the matching read API: transfers via `GET /v2/transfers/{transferId}`; deposits and withdrawals via `GET /v2/transactions/{id}`.
Read `transactionType` (`DEPOSIT`, `WITHDRAW`, or `TRANSFER`) together with `sourceAddresses` and `destinationAddresses` to classify what happened and where the funds moved.
### Tell an internal deposit from an external one
An internal transfer between your own wallets lands as a `DEPOSIT` on the destination wallet, the same shape as a deposit from an outside sender. To distinguish them, compare the deposit's `sourceAddresses` against the addresses you manage (from `GET /v2/wallets` and the addresses API): a match means the funds came from one of your own wallets; otherwise the sender is external.
The transfers API identifies records by `transferId`, which isn't always a UUID. Match on the value exactly as returned rather than assuming a format.
## Idempotency and retries
Provide an `idempotentId` per request so an interrupted call can be retried safely without double-spending. For status codes, rate limits, and cursor pagination, see [Handling errors, retries, and pagination](/knowledge-base/api-reference/errors-pagination).
# Overview
Source: https://docs.anchorage.com/knowledge-base/platform/developers/move-money/overview
Understand how deposits, transfers, and withdrawals work within Anchorage Digital's security model.
At Anchorage Digital, every movement runs through the same controls that secure the assets themselves: segregated, HSM-secured vaults governed by policy-based quorum. The money-movement APIs are built so you can automate and scale movement without stepping outside that security model.
Funds come **in** through a deposit, sit in your wallets and vaults, and move **out** in one of two ways. Which way you use depends on two things: how much per-transaction control you want, and where the funds are going.
## Start here
* **Receive funds** — Create wallets and deposit addresses to bring digital assets or USD into Anchorage Digital. See [Deposit](/knowledge-base/platform/developers/move-money/deposit).
* **Transfer** — Move assets between your wallets or to a trusted destination, without per-transaction quorum. See [Transfer](/knowledge-base/platform/developers/move-money/transfer).
* **Withdraw** — Move assets with quorum approval on every request. See [Withdraw](/knowledge-base/platform/developers/move-money/withdraw).
## The mental model
A deposit is the only way funds enter Anchorage Digital, and receiving never requires quorum. Everything else is a movement out of—or between—your holdings. There are exactly two kinds, split by approval model.
**Transfers** move assets without quorum approval on each request, which suits recurring or high-frequency flows. In exchange, they require one-time setup: an allowlisted destination and a permission group scoped to the operation.
**Withdrawals** require quorum approval on every request, giving you control over each individual movement through your vault policies.
Both transfers and withdrawals can go to an **internal** wallet you own or to an **external** destination outside Anchorage Digital. External movements add two requirements: the destination must be an allowlisted trusted destination, and the request must carry AML questionnaire information for the transaction and recipient.
This guide assumes you're familiar with quorum and approval rules. If you're not, start with [vault policies](/knowledge-base/platform/users/vault-policies).
## Where quorum applies
| Action | Quorum on each request? |
| :--------------------------------------- | :---------------------------------------------- |
| Deposit (receive) | |
| Transfer (internal or external) | (approval is front-loaded into setup) |
| Withdrawal (internal or external) | |
| Adding or removing a trusted destination | |
## Support at a glance
### Move money support
| | Internal transfer API | External transfer API | Withdrawal API |
| :----------------- | :-------------------- | :-------------------- | :------------- |
| **Digital assets** | | | |
| **USD** | | | |
Deposits are supported for both digital assets and USD. Trusted destinations for digital assets can be managed via API and the web platform. USD (fiat) trusted destinations are managed in the web platform today.
### Trusted destination required
Trusted destinations (allowlisted addresses and bank recipients) let you pre-approve an external destination for use across the iOS app, web dashboard, and APIs.
| | Internal transfer API | External transfer API | Withdrawal API |
| :----------------- | :-------------------- | :-------------------- | :------------- |
| **Digital assets** | | | \* |
| **USD** | | | \* |
If you want to restrict Withdrawal API destinations to only trusted/allowlisted addresses, reach out to your point of contact to enable this.
## Before you move money: prerequisites
Internal movements work with standard API access. External movements—external transfers and withdrawals to new destinations—require one-time setup, and quorum is required at several of these steps.
1. **Allowlist a trusted destination** — Pre-approve the external address or bank recipient. Adding a trusted destination requires quorum approval. See [Trusted destinations](/knowledge-base/platform/developers/move-money/setup/trusted-destinations).
2. **Configure external transfer permissions** — Enable external transfers on the permission group the key uses. This permission is configurable: scope it to specific trusted destinations, or allow any quorum-approved trusted destination. See [Permission groups and API keys](/knowledge-base/platform/developers/move-money/setup/permission-groups).
3. **Create and activate an API key** — API keys with external transfer or withdrawal permissions require quorum approval before they can be used. See [Authentication](/knowledge-base/platform/developers/move-money/setup/authentication).
4. **Include AML information** — External transfers and withdrawals carry AML questionnaire information in the request payload. See [AML questionnaire](/knowledge-base/platform/developers/move-money/setup/aml-questionnaire).
Keep internal and external transfer permissions in separate permission groups and API keys. Do not combine them.
## Related
* [Transfers vs. withdrawals](/knowledge-base/platform/developers/move-money/transfers-vs-withdrawals) — The full comparison of the two approval models.
* [Trusted destinations](/knowledge-base/platform/developers/move-money/setup/trusted-destinations) — Allowlist external addresses and bank recipients.
* [Network and gas fees](/knowledge-base/platform/developers/network-gas-fees) — How blockchain fees work and how the gas station handles them.
# AML questionnaire
Source: https://docs.anchorage.com/knowledge-base/platform/developers/move-money/setup/aml-questionnaire
Understand and complete the compliance payload required on every external transfer and withdrawal.
External transfers and withdrawals carry an AML questionnaire describing the originator, destination, and recipient. Internal movements don't need it. Use the key that matches your operation:
| Operation | Key |
| :-------------------- | :--------------------------- |
| External transfer API | `transferAmlQuestionnaire` |
| Withdrawal API | `withdrawalAmlQuestionnaire` |
All fields have a 256-character maximum. Some fields are conditional on others.
## How to fill it
**1. `destinationType`** — Where the destination is hosted.
* **`FINANCIAL_INSTITUTION`** — A third party holds the key (for example, an exchange). Requires `institutionName` and `institutionCountry`.
* **`SELFHOSTED_WALLET`** — The owner holds the key. Requires `selfhostedDescription`.
**2. `recipientType`** — Who receives the funds.
* **`DESTINATION_INSTITUTION`** — The financial institution named in `institutionName`.
* **`MY_ORGANIZATION`** — Your own organization.
* **`PERSON`** — Requires `recipientFirstName`, `recipientLastName`, and `recipientCountry`.
* **`ENTITY`** — Requires `recipientFullName` and `recipientCountry`.
**3. `originatorType`** — Who initiated the move.
* **`MY_ORGANIZATION`** — Your API key initiated the move and assets aren't being moved on behalf of a client.
* **`MY_CLIENT`** — Your key is acting as a financial institution on a client's behalf. The `originator` address fields are then required.
**4. `purpose`** — `TRADING_SETTLEMENT`, `LENDING`, `INVESTMENT`, `EXPENSES`, `FEE_PAYMENT`, `GRANT_PAYMENT`, `PRIZE_AWARD`, `GIFT`, `REIMBURSEMENT`, `REBALANCE`, or `INTRA_COMPANY`.
## Reduced AML for trusted destinations
If the destination is a trusted destination that already carries AML details, set `useTrustedDestinationAml: true` and provide only `originatorType` and `purpose`. The rest is inherited.
```json theme={null}
"withdrawalAmlQuestionnaire": {
"useTrustedDestinationAml": true,
"originatorType": "MY_ORGANIZATION",
"purpose": "INVESTMENT"
}
```
## Field reference
| Field | Required when |
| :------------------------------------------------------------------------------------------------------------------------------------ | :------------------------------------------------------ |
| `originatorType` | Always. `MY_ORGANIZATION` or `MY_CLIENT`. |
| `originatorName`, `originatorCountry`, `originatorStreetAddress`, `originatorPostalCode`, `originatorCity`, `originatorStateProvince` | `originatorType: MY_CLIENT`. |
| `destinationType` | Always. `FINANCIAL_INSTITUTION` or `SELFHOSTED_WALLET`. |
| `institutionName`, `institutionCountry` | `destinationType: FINANCIAL_INSTITUTION`. |
| `selfhostedDescription` | `destinationType: SELFHOSTED_WALLET`. |
| `recipientType` | Always. |
| `recipientFirstName`, `recipientLastName` | `recipientType: PERSON`. |
| `recipientFullName` | `recipientType: ENTITY`. |
| `recipientCountry` | `recipientType: PERSON` or `ENTITY`. |
| `recipientStreetAddress`, `recipientCity` | Each is required if the other is sent. |
| `purpose` | Always. |
## Institution / country mapping
| Institution | Country |
| :--------------------- | :------ |
| Altonomy | SG |
| Amber Group | SG |
| Anchorage Digital Bank | US |
| B2C2 | UK |
| Binance | HK |
| Binance.US | US |
| BitGo | US |
| BitKub | TH |
| Bittrex | US |
| Bitwage | US |
| Circle | US |
| Coinbase | US |
| CoinList | US |
| Copper | GB |
| Cross Tower | US |
| Cross Tower Bermuda | BM |
| Cumberland | US |
| Deribit | PA |
| DV Chain | US |
| FalconX | US |
| Fidelity | US |
| Fireblocks | US |
| Floating Point Group | US |
| Flow Traders | NL |
| FXCH | IE |
| Galaxy Digital | US |
| Gemini | US |
| Genesis | US |
| GSR | HK |
| Hex Trust | HK |
| Huobi | SC |
| Jane Street | US |
| Kraken | US |
| NYDIG | US |
| OKX | SC |
| OSL | HK |
| PrimeTrust | US |
| Tokenomy | SG |
| Wintermute | UK |
| Zap Solutions, Inc. | US |
# Authentication and request signing
Source: https://docs.anchorage.com/knowledge-base/platform/developers/move-money/setup/authentication
Authenticate every API request and sign sensitive move-money operations with Ed25519.
Every request includes your `Api-Access-Key` header. Sensitive operations—including transfers, withdrawals, and trusted-destination management—additionally require an **Ed25519 request signature**, supplied in the `Api-Signature` and `Api-Timestamp` headers and generated from your private key over the canonical request.
## Base URLs
| Environment | Base URL |
| :---------- | :------------------------------------- |
| Production | `https://api.anchorage.com/v2` |
| Sandbox | `https://api.anchorage-staging.com/v2` |
For the exact signing recipe and code samples, see [Signing requests](/knowledge-base/platform/developers/request-signing). For how authentication, keys, and permission groups fit together, see [Setting up](/knowledge-base/platform/developers/setting-up).
# Permission groups and API keys
Source: https://docs.anchorage.com/knowledge-base/platform/developers/move-money/setup/permission-groups
Configure the permissions and API keys needed for transfers, withdrawals, and trusted destination management.
An **API key** authenticates requests. A **permission group** controls which vaults and operations the keys in it can use. Move-money setup is mostly a matter of putting the right permissions on the right group, then activating a key against it.
## Permission levels
* **Global permissions** apply across all your vaults (for example, `Initiate withdrawals`).
* **Vault-level permissions** apply only to the selected vault or its wallets (for example, `Transfer funds`).
## Move-money permissions
| Permission | Level | Used for |
| :---------------------------------------------- | :----- | :-------------------------------------------------------------- |
| `Read` | Vault | Reading balances and transactions. |
| `Create address` | Vault | Creating wallets and deposit addresses. |
| `Transfer funds (within Anchorage Digital)` | Vault | Internal transfers from that vault. |
| `Transfer funds (outside of Anchorage Digital)` | Vault | External transfers from that vault. |
| `Initiate withdrawals` | Global | Withdrawals to external destinations (each still needs quorum). |
| `Manage trusted destinations` | Global | Creating and managing trusted destinations. |
| `Deposit attribution` | Global | Attributing deposits as known or spam. |
| `Configure webhooks` | Global | Managing webhooks. |
## Activation and segregation
* Keys with external transfer or withdrawal permissions require quorum approval before they can be used.
* Keep internal and external transfer permissions in separate permission groups and API keys. Do not combine them.
* An optional daily transfer limit can be set per permission group, applied across all keys in the group over a rolling 24-hour window. Limits apply per permission group only. Per-account limits spanning multiple endpoints aren't available yet.
Permission groups are created and configured by your organization admin in the web dashboard. See [API keys](/knowledge-base/platform/developers/api-keys) for creating and using keys.
# Trusted destinations
Source: https://docs.anchorage.com/knowledge-base/platform/developers/move-money/setup/trusted-destinations
Allowlist external addresses and bank recipients before making external transfers or withdrawals.
A **trusted destination** is an allowlisted external address or USD bank recipient. Adding one requires quorum approval. Once allowlisted, it can be used across the iOS app, web dashboard, and APIs.
## What you can do where
| Operation | API | Web dashboard |
| :------------------------------------------- | :-------- | :------------ |
| View trusted destinations | | |
| Create (digital assets) | | |
| Create (USD bank recipient) | | |
| Delete | | |
| Edit | | |
| Batch upload | | |
| Network-level destination (`isNetworkLevel`) | | |
For USD bank recipients, add them in the web dashboard by selecting **Fiat** as the type. For the step-by-step flow, see [Adding a USD trusted destination](/knowledge-base/platform/users/usd-banking#adding-a-usd-trusted-destination) in the USD banking guide. You can list fiat trusted destinations via API today by filtering on `type == "fiat"`.
Creating, editing, and deleting fiat trusted destinations via API is in development. This section will be updated with endpoints and examples once it's available for testing.
## Sending to your own org's addresses
You can allowlist addresses that belong to your own organization as trusted destinations to tag and label critical internal addresses. This is purely a convenience for recognition — it isn't required for internal movement.
If your concern is avoiding per-transaction quorum when moving assets between your own wallets, use the [internal transfer API](/knowledge-base/platform/developers/move-money/transfer/crypto#internal-transfer) instead. Internal transfers set both `source.type` and `destination.type` to `WALLET` and don't require a trusted destination, allowlisting, or AML information.
## Create a trusted destination via API
Requires the `Manage Trusted Destinations` permission. Adding a trusted destination requires quorum approval.
```json theme={null}
// POST /v2/trusted_destinations
{
"idempotentId": "{unique ID}",
"trustedDestinations": [
{
"address": "{address}",
"assetType": "{asset}",
"name": "{name}",
"description": "{description}",
"isNetworkLevel": true,
"memo": "{memo}",
"trustedDestinationAmlQuestionnaire": {
"destinationType": "FINANCIAL_INSTITUTION",
"institutionName": "{institution name}",
"institutionCountry": "US",
"recipientType": "MY_ORGANIZATION"
}
}
]
}
```
Set `isNetworkLevel: true` to let the destination receive any asset on that network (digital assets only).
## `trustedDestinationAmlQuestionnaire` fields
Required for Anchorage Digital Bank clients adding trusted destinations via API.
Omit `trustedDestinationAmlQuestionnaire` entirely for Porto organizations — including it, even as an empty object, causes the request to fail.
| Field | Description | Required when |
| :----------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------- | :----------------------------------------------------------------------------------------------------- |
| `destinationType` | `FINANCIAL_INSTITUTION` (for example, a crypto exchange) or `SELFHOSTED_WALLET` (for example, a hardware or browser wallet). | Always |
| `institutionName` | Name of the institution receiving the withdrawal. | `destinationType` is `FINANCIAL_INSTITUTION` |
| `institutionCountry` | Two-letter country code where the institution is incorporated. | `destinationType` is `FINANCIAL_INSTITUTION` |
| `selfhostedDescription` | Description of the self-hosted wallet. | `destinationType` is `SELFHOSTED_WALLET` |
| `selfhostedWalletOwner` | Owner of the self-hosted wallet: `MY_ORGANIZATION` or `PERSON_OR_ENTITY`. | Optional, when `destinationType` is `SELFHOSTED_WALLET` |
| `recipientType` | Ultimate beneficiary: `DESTINATION_INSTITUTION`, `MY_ORGANIZATION`, `PERSON`, or `ENTITY`. Use `MY_ORGANIZATION` for your own address at an exchange. | Always |
| `recipientFirstName` | First name of the beneficiary. | `recipientType` is `PERSON` |
| `recipientLastName` | Last name of the beneficiary. | `recipientType` is `PERSON` |
| `recipientFullName` | Full name of the beneficiary entity. | `recipientType` is `ENTITY` |
| `recipientCountry` | Two-letter country code of the beneficiary. | `recipientType` is `PERSON` or `ENTITY` |
| `recipientStreetAddress` | Street address of the beneficiary. | Optional, when `recipientType` is `PERSON` or `ENTITY` — required once `recipientCity` is set |
| `recipientCity` | City of the beneficiary. | Optional, when `recipientType` is `PERSON` or `ENTITY` — required once `recipientStreetAddress` is set |
| `recipientStateProvince` | State or province of the beneficiary. | Optional, when `recipientType` is `PERSON` or `ENTITY` |
| `recipientPostalCode` | Postal code of the beneficiary. | Optional, when `recipientType` is `PERSON` or `ENTITY` |
Answer the questions below in order to see exactly which fields apply to your case, and the resulting payload:
## Connect a trusted destination to an API key
If you're using the Transfers API to transfer to a trusted destination, you need to configure your API key's permission group to allow it. There are two options, set when configuring the **Transfers outside Anchorage** permission on your API key.
### Specific destinations (default)
By default, your API key is scoped to **Specific destinations**. Once a trusted destination has been added and approved, you must also add it to the API key's permission group before you can transfer to it. See [Permission groups and API keys](/knowledge-base/platform/developers/move-money/setup/permission-groups) for the step-by-step flow.
Fiat trusted destinations can't be added to a permission group's specific-destinations list. If you're transferring USD to bank recipients via the Transfers API, you must select **Any trusted destination** instead.
### Any trusted destination
You can select **Any trusted destination** when configuring your key to automatically allowlist all current and future trusted destinations for that key. This removes the need to manually update the permission group each time a new trusted destination is approved. This option is required for [USD transfers](/knowledge-base/platform/developers/move-money/transfer/usd#external-transfer) to fiat trusted destinations.
## APIs
| API | Description |
| :----------------------------------- | :---------------------------------------------------------------------------- |
| List trusted destinations | Returns trusted destinations. Filter on `type == "fiat"` for bank recipients. |
| Create new trusted destinations | Allowlists one or more destinations. Requires quorum approval. |
| Check status of trusted destinations | Returns the approval status of a pending destination. |
| Delete trusted destination | Removes a destination. |
# Crypto transfer
Source: https://docs.anchorage.com/knowledge-base/platform/developers/move-money/transfer/crypto
Move digital assets between wallets or to an external on-chain address without per-transaction quorum.
A crypto transfer moves digital assets to an internal wallet or an external on-chain address without quorum approval on each request. For shared concepts, external setup, limits, and status monitoring, see [Transfer](/knowledge-base/platform/developers/move-money/transfer). This page covers the crypto-specific payloads and behavior.
`POST /v2/transfers` requires the `Transfer funds` permission and an Ed25519 request signature.
## Internal transfer
Move assets to any wallet you own at Anchorage Digital. No allowlisting or AML information is required. Set both `source.type` and `destination.type` to `WALLET`.
```json theme={null}
{
"source": {
"id": "{source wallet ID}",
"type": "WALLET"
},
"destination": {
"id": "{destination wallet ID}",
"type": "WALLET"
},
"assetType": "{asset}",
"amount": "{quantity}",
"transferMemo": "{memo}",
"idempotentId": "{unique ID}"
}
```
## External transfer
Move assets to an external destination that has been allowlisted as a trusted destination. External transfers always include a transfer AML questionnaire. You can identify the destination two ways:
* **`ADDRESS`** — Pass the allowlisted address as `destination.id`. If the asset requires a memo or destination tag, include the matching `assetParameters`.
* **`TRUSTED_DESTINATION`** — Pass the trusted destination ID as `destination.id`. Any memo or destination tag stored on the trusted destination is applied automatically, so you don't submit `assetParameters` yourself. This is the simpler path for assets that need a memo or tag, and it avoids mismatched-memo errors.
```json By address theme={null}
{
"source": {
"id": "{source wallet ID}",
"type": "WALLET"
},
"destination": {
"id": "{trusted destination address}",
"type": "ADDRESS"
},
"assetType": "{asset}",
"amount": "{quantity}",
"transferMemo": "{memo}",
"idempotentId": "{unique ID}",
"transferAmlQuestionnaire": {
"purpose": "{purpose}",
"originatorType": "{originatorType}"
},
"assetParameters": "{memo or destination tag, if required}"
}
```
```json By trusted destination theme={null}
{
"source": {
"id": "{source wallet ID}",
"type": "WALLET"
},
"destination": {
"id": "{trusted destination ID}",
"type": "TRUSTED_DESTINATION"
},
"assetType": "{asset}",
"amount": "{quantity}",
"transferMemo": "{memo}",
"idempotentId": "{unique ID}",
"transferAmlQuestionnaire": {
"purpose": "{purpose}",
"originatorType": "{originatorType}"
}
}
```
### Fields
| Field | Description |
| :-------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `source.id` / `source.type` | The wallet to send from. Retrieve wallet IDs via `GET /v2/wallets`. |
| `destination.type` | `WALLET` for internal. For external, `ADDRESS` (the allowlisted address as `destination.id`) or `TRUSTED_DESTINATION` (the trusted destination ID as `destination.id`). |
| `assetType` | The asset to move. List supported values via `GET /v2/asset-types`. |
| `amount` | Quantity as a string, without units. |
| `idempotentId` | A client-provided unique ID (for example, a v4 UUID). Use a distinct value per transfer so an interrupted call can be safely retried. |
| `transferMemo` | Optional free-text description carried into the resulting transaction and deposit. |
| `transferAmlQuestionnaire` | Required on external transfers. See [AML questionnaire](/knowledge-base/platform/developers/move-money/setup/aml-questionnaire) for the full field set. |
### Response
A successful request returns `201` with a `transferId` and `status`:
```json theme={null}
{
"data": {
"transferId": "008d3ec72558ce907571886df63ef51594b5bd8cf106a0b7fa8f12a30dfc867f",
"status": "QUEUED"
}
}
```
With `destination.type: ADDRESS`, include the matching `assetParameters` if the asset requires a memo or destination tag. With `destination.type: TRUSTED_DESTINATION`, omit `assetParameters`—the memo or tag stored on the trusted destination is applied automatically.
## Crypto-specific behavior
**Queuing** — Up to 50 transfer requests from the same source wallet can be queued at once. Transfers for the same asset on the same blockchain process one at a time; others stay `QUEUED` until the prior transfer completes or fails. Transfers on different wallets or different blockchains can process in parallel. Transfers expire 24 hours after initiation.
**`assetParameters`** — Required when transferring to institutional wallets that need a memo or destination tag. Supported assets: ATOM, Cosmos, DYDX, HBAR, STX, TIA, XLM, XRP, ZETA.
**`useGasStation`** — If `true`, Anchorage Digital's gas station pays network fees for supported assets and organizations. Processing is slightly slower, since Anchorage Digital prefunds the originating wallet before executing the transfer.
**`deductFeeFromAmountIfSameType`**
| Value | Behavior |
| :---------------- | :-------------------------------------------------------------------------------------------------- |
| `false` (default) | Network fee is charged in addition to the transfer amount. |
| `true` | Network fee is deducted from the transfer amount, only when the fee and transfer asset types match. |
To transfer a full balance of an asset whose fee is paid in the same asset (for example, BTC), set `deductFeeFromAmountIfSameType: true`. When the source is a `walletId`, fees are deducted from that wallet; when the source is a `vaultId`, fees come from the vault's default wallet (`isDefault: true`).
## Troubleshooting
If an external transfer returns `401`/`403`, check that:
* You're using the correct base URL.
* The destination is an allowlisted trusted destination.
* The permission group has external transfers enabled.
* If your permission is scoped to specific destinations, the destination has been connected to the permission group and endorsed.
Common request-level failures: the source wallet doesn't exist or doesn't support the asset, the amount exceeds available funds, the destination doesn't support the asset, or the key lacks permissions for the source vault.
After a request succeeds, the transfer can still fail at execution if there are insufficient funds to cover the network fee at broadcast time or there's a blockchain-level failure.
# USD transfer
Source: https://docs.anchorage.com/knowledge-base/platform/developers/move-money/transfer/usd
Move USD between accounts or to a bank trusted destination without per-transaction quorum.
A USD transfer moves funds between accounts you own (internal) or to a bank trusted destination (external), without quorum approval on each request. For shared concepts, external setup, limits, and status monitoring, see [Transfer](/knowledge-base/platform/developers/move-money/transfer). This page covers the USD-specific payloads.
`POST /v2/transfers` requires the `Transfer funds` permission and an Ed25519 request signature.
Staging uses the `USD_R` asset type and `https://api.anchorage-staging.com/v2`. Production uses `USD` and `https://api.anchorage.com/v2`. The examples below show the staging value.
## Internal transfer
Move USD between wallets you own. Set both `source.type` and `destination.type` to `WALLET`. No trusted destination or AML information is required.
```json theme={null}
{
"source": {
"id": "{source wallet ID}",
"type": "WALLET"
},
"destination": {
"id": "{destination wallet ID}",
"type": "WALLET"
},
"assetType": "USD_R",
"amount": "{quantity}",
"transferMemo": "{memo}",
"idempotentId": "{unique ID}"
}
```
## External transfer
Move USD to a bank trusted destination. Set `destination.type` to `TRUSTED_DESTINATION` and `destination.id` to a fiat trusted destination ID, and include `assetParametersFiatTrustedDestination`.
Your API key's permission group must have **Any trusted destination** selected under **Transfers outside Anchorage**. Fiat trusted destinations can't be added individually to a permission group's specific-destinations list. See [Connect a trusted destination to an API key](/knowledge-base/platform/developers/move-money/setup/trusted-destinations#connect-a-trusted-destination-to-an-api-key) for details.
To find the destination ID, call `GET /v2/trusted_destinations` and filter on `type == "fiat"`.
```json theme={null}
{
"source": {
"id": "{source wallet ID}",
"type": "WALLET"
},
"destination": {
"id": "{fiat trusted destination ID}",
"type": "TRUSTED_DESTINATION"
},
"assetType": "USD_R",
"amount": "{quantity}",
"transferMemo": "{memo}",
"assetParametersFiatTrustedDestination": {
"purpose": "{purpose}",
"memo": "{note to beneficiary}"
}
}
```
### Fields
| Field | Description |
| :---------------------------------------------- | :--------------------------------------------------------------------------------------------------------- |
| `source.id` | The source USD wallet. Retrieve wallet IDs via `GET /v2/wallets`. |
| `destination.id` | Destination wallet ID (internal) or fiat trusted destination ID (external). |
| `destination.type` | `WALLET` for internal, `TRUSTED_DESTINATION` for external. |
| `amount` | USD amount as a string. |
| `transferMemo` | Optional free-text description attached to the transfer. |
| `idempotentId` | A client-provided unique ID. Use a distinct value per transfer. |
| `assetParametersFiatTrustedDestination.purpose` | Required on external transfers. Classifies the reason for the transfer (see enum below). |
| `assetParametersFiatTrustedDestination.memo` | Optional note to beneficiary, max 140 characters. If omitted, the memo on the trusted destination is used. |
### `purpose` values
`TRADING_SETTLEMENT` | `LENDING` | `INVESTMENT` | `EXPENSES` | `FEE_PAYMENT` | `GRANT_PAYMENT` | `PRIZE_AWARD` | `GIFT` | `REIMBURSEMENT` | `REBALANCE` | `INTRA_COMPANY`
### Response
A successful request returns `201` with a `transferId` and `status`:
```json theme={null}
{
"data": {
"transferId": "008d3ec72558ce907571886df63ef51594b5bd8cf106a0b7fa8f12a30dfc867f",
"status": "QUEUED"
}
}
```
## Managing bank trusted destinations
Listing fiat trusted destinations via API is supported. Creating, editing, and deleting them via API is in development. Add bank recipients in the web dashboard today by selecting **Fiat** as the destination type—see [Adding a USD trusted destination](/knowledge-base/platform/users/usd-banking#adding-a-usd-trusted-destination). For API details, see [Trusted destinations](/knowledge-base/platform/developers/move-money/setup/trusted-destinations).
# Transfers and withdrawals
Source: https://docs.anchorage.com/knowledge-base/platform/developers/move-money/transfers-vs-withdrawals
Two approval models for moving assets out of Anchorage Digital.
Both transfers and withdrawals move assets out of—or between—your holdings, for both USD and digital assets. The difference is the approval model, and that choice drives the setup, the destinations you can reach, and the controls on each movement.
## Transfers
A transfer moves assets without quorum approval on each request, which suits recurring or high-frequency flows. Approval is front-loaded into one-time setup: an allowlisted destination and a permission group scoped to the operation. Transfers reach internal wallets and external destinations.
## Withdrawals
A withdrawal requires quorum approval on every request, giving you granular control over each movement through your vault policies. Because each withdrawal is approved individually, the destination doesn't need to be allowlisted in advance.
## Asset support
| | Internal transfer API | External transfer API | Withdrawal API |
| :----------------- | :-------------------- | :-------------------- | :------------- |
| **Digital assets** | | | |
| **USD** | | | |
## Feature comparison
| | Internal transfer | External transfer | Withdrawal |
| :--------------------------------------------------------------- | :------------------------ | :----------------------------------------- | :--------------------------------------------------- |
| Quorum required (per request) | | | |
| Destination | Wallets you own | Allowlisted address or trusted destination | Any address, trusted destination, or internal wallet |
| Pre-allowlisted destination required | | | |
| Trusted destination bound to permission group | | Configurable | |
| AML information required | | | |
| Memo or tag inherited from trusted destination | n/a | | |
| Queued | Yes (up to 50 per source) | Yes | No (one at a time) |
| Deduct network fee from amount (`deductFeeFromAmountIfSameType`) | | | |
| Gas station (`useGasStation`) | | | |
## Source and destination options
| Operation | Source | Destination |
| :---------------- | :------- | :-------------------------------------------- |
| Internal transfer | `WALLET` | `WALLET` |
| External transfer | `WALLET` | `ADDRESS` or `TRUSTED_DESTINATION` |
| Withdrawal | `WALLET` | `WALLET`, `ADDRESS`, or `TRUSTED_DESTINATION` |
Prefer `WALLET` over `VAULT`. When a `VAULT` is specified, the system selects the first-created wallet in the vault for the asset, even if that wallet has been archived. Use `VAULT` only when a single wallet per asset is maintained. The `VAULT` type will be deprecated in the future.
## When a transfer queues
Queuing is keyed to the **source wallet**—never the vault, and never the destination. A transfer is held as `QUEUED` only when another movement is already in flight from the same source wallet:
* A **withdrawal pending** from that source wallet holds subsequent transfers until the withdrawal is broadcast or cancelled.
* A **transfer in progress** from that source wallet holds additional transfers behind it; they appear in the activity log. Up to 50 transfers can be queued per source wallet.
Activity on the *destination* never queues a transfer. Sending from wallet A to wallet B doesn't queue just because wallet B has a pending withdrawal. For the per-asset and per-blockchain specifics, see [Crypto transfer](/knowledge-base/platform/developers/move-money/transfer/crypto).
Withdrawals themselves don't queue. If a withdrawal is already ongoing from a source wallet, a new withdrawal request from that wallet fails rather than waiting in line.
To keep quorum-pending withdrawals from blocking automated settlement, isolate withdrawals in a dedicated wallet. Settlement transfers from your settlement wallet then run without waiting on withdrawal approvals elsewhere.
## The same move, two ways
Moving 1 ETH to a destination you've allowlisted—first as a transfer (no per-request approval), then as a withdrawal (quorum on each request):
```json Transfer — POST /v2/transfers theme={null}
{
"source": { "id": "{source wallet ID}", "type": "WALLET" },
"destination": { "id": "{trusted destination ID}", "type": "TRUSTED_DESTINATION" },
"assetType": "ETH",
"amount": "1",
"idempotentId": "{unique ID}",
"transferAmlQuestionnaire": { "purpose": "{purpose}", "originatorType": "{originatorType}" }
}
```
```json Withdrawal — POST /v2/transactions/withdrawal theme={null}
{
"source": { "id": "{source wallet ID}", "type": "WALLET" },
"destination": { "id": "{trusted destination ID}", "type": "TRUSTED_DESTINATION" },
"assetType": "ETH",
"amount": "1",
"idempotentId": "{unique ID}",
"withdrawalAmlQuestionnaire": { "useTrustedDestinationAml": true, "originatorType": "MY_ORGANIZATION", "purpose": "INVESTMENT" }
}
```
The transfer clears without a per-request approval because the destination and permission group were authorized up front; the withdrawal routes to quorum approval before it broadcasts. See [Crypto transfer](/knowledge-base/platform/developers/move-money/transfer/crypto) and [Crypto withdrawal](/knowledge-base/platform/developers/move-money/withdraw/crypto) for full payloads and fields.
## Which to use
Choose a **transfer** when you want automated, repeatable movement and you've pre-authorized the destination and permissions. Choose a **withdrawal** when you want a human quorum checkpoint on each movement, or you're sending to a one-off destination you don't want to allowlist.
For full API details, see [Transfer](/knowledge-base/platform/developers/move-money/transfer) and [Withdraw](/knowledge-base/platform/developers/move-money/withdraw).
# Crypto withdrawal
Source: https://docs.anchorage.com/knowledge-base/platform/developers/move-money/withdraw/crypto
Move digital assets out of a wallet with quorum approval on every request.
A crypto withdrawal moves digital assets out of a wallet with quorum approval on every request. For the shared model, the approval workflow, status values, and fees, see [Withdraw](/knowledge-base/platform/developers/move-money/withdraw). This page covers the crypto-specific payloads.
`POST /v2/transactions/withdrawal` requires the `Initiate withdrawals` permission and an Ed25519 request signature.
## AML questionnaire options
External withdrawals carry AML questionnaire information. You can supply it two ways:
* **Inline** — Provide the full `withdrawalAmlQuestionnaire` with originator, recipient, and destination details. Use this for any external address.
* **Inherited from a trusted destination** — If the destination is allowlisted as a trusted destination, set `withdrawalAmlQuestionnaire.useTrustedDestinationAml` to `true`. The system applies the beneficiary and destination details stored on the trusted destination, so you only provide `originatorType` and `purpose`.
```json Inline AML theme={null}
{
"amount": "{quantity}",
"assetType": "{asset}",
"source": {
"id": "{source wallet ID}",
"type": "WALLET"
},
"destination": {
"id": "{external address}",
"type": "ADDRESS"
},
"description": "{description}",
"useGasStation": false,
"withdrawalAmlQuestionnaire": {
"destinationType": "SELFHOSTED_WALLET",
"recipientType": "PERSON",
"purpose": "INVESTMENT",
"originatorType": "MY_ORGANIZATION",
"selfhostedDescription": "{wallet description}",
"recipientFirstName": "{first name}",
"recipientLastName": "{last name}",
"recipientFullName": "{full name}",
"recipientCountry": "US",
"recipientStreetAddress": "{street}",
"recipientCity": "{city}",
"recipientStateProvince": "{state}",
"recipientPostalCode": "{postal code}"
}
}
```
```json Inherited from trusted destination theme={null}
{
"idempotentId": "{unique ID}",
"amount": "{quantity}",
"assetType": "{asset}",
"source": {
"id": "{source wallet ID}",
"type": "WALLET"
},
"destination": {
"id": "{trusted destination ID}",
"type": "TRUSTED_DESTINATION"
},
"description": "{description}",
"useGasStation": false,
"withdrawalAmlQuestionnaire": {
"useTrustedDestinationAml": true,
"originatorType": "MY_ORGANIZATION",
"purpose": "INVESTMENT"
}
}
```
### Fields
| Field | Description |
| :--------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `amount` | Quantity as a string, without units. |
| `assetType` | The asset to withdraw. List supported values via `GET /v2/asset-types`. |
| `source` | The wallet to withdraw from (`type: WALLET`). |
| `destination.type` | `ADDRESS` for an external address, `TRUSTED_DESTINATION` for an allowlisted destination, or `WALLET` for an internal wallet. |
| `description` | Optional context, visible in the iOS app and not published on-chain. |
| `idempotentId` | Optional client-provided unique ID for safe retries. |
| `useGasStation` | If `true`, Anchorage Digital pays network fees for supported assets and organizations. |
| `withdrawalAmlQuestionnaire` | Required for external withdrawals. Provide inline, or set `useTrustedDestinationAml: true` to inherit from a trusted destination. See [AML questionnaire](/knowledge-base/platform/developers/move-money/setup/aml-questionnaire). |
For assets that use a memo or destination tag, the value is inherited automatically when you withdraw to a trusted destination—you don't provide `assetParameters` yourself.
### Response
A successful request returns `201` with a `withdrawalId`:
```json theme={null}
{
"data": {
"withdrawalId": "8696144cca28a634c05858d00e51191408498a7808a837fc4645b4b6997dde09"
}
}
```
Track status through the transactions API. See [Track movement status](/knowledge-base/platform/developers/move-money/operate/track-status).
## UTXO assets
For UTXO-based assets, Anchorage Digital exposes a single wallet-level address as the representative address and selects UTXOs randomly across the wallet's addresses to preserve privacy. Sub-UTXO balances remain visible on-chain.
## Troubleshooting
Withdrawals are not queued: a request fails if one is already ongoing for the source. Other request-level failures include an unknown asset, an amount that exceeds available funds (including fees), an invalid destination address, or a key without withdrawal permissions for the vault.
If a withdrawal fails when specified at the wallet or address level, try specifying the source at the vault level with a vault ID.
After quorum approval, a withdrawal can still fail at execution if there are insufficient funds for the network fee or there's a blockchain-level failure.
# USD withdrawal
Source: https://docs.anchorage.com/knowledge-base/platform/developers/move-money/withdraw/usd
Move USD from a wallet to a bank trusted destination with quorum approval on every request.
A USD withdrawal moves funds from a USD wallet to a bank trusted destination, with quorum approval on every request. For the shared model, the approval workflow, status values, and monitoring, see [Withdraw](/knowledge-base/platform/developers/move-money/withdraw). This page covers the USD-specific payload.
`POST /v2/transactions/withdrawal` requires the `Initiate withdrawals` permission and an Ed25519 request signature.
Staging uses the `USD_R` asset type and `https://api.anchorage-staging.com/v2`. Production uses `USD` and `https://api.anchorage.com/v2`. The example below shows the staging value.
## Send USD to a bank
Set `destination.type` to `TRUSTED_DESTINATION` and `destination.id` to a fiat trusted destination ID, and include `assetParametersFiatTrustedDestination`. To find the destination ID, call `GET /v2/trusted_destinations` and filter on `type == "fiat"`.
```json theme={null}
{
"amount": "{quantity}",
"assetType": "USD_R",
"source": {
"id": "{source wallet ID}",
"type": "WALLET"
},
"destination": {
"id": "{fiat trusted destination ID}",
"type": "TRUSTED_DESTINATION"
},
"assetParametersFiatTrustedDestination": {
"purpose": "{purpose}",
"memo": "{note to beneficiary}"
}
}
```
### Fields
| Field | Description |
| :---------------------------------------------- | :--------------------------------------------------------------------------------------------------------- |
| `amount` | USD amount as a string. |
| `source.id` | The source USD wallet. Retrieve via `GET /v2/wallets`. |
| `destination.id` | A fiat trusted destination ID. |
| `assetParametersFiatTrustedDestination.purpose` | Required. Classifies the reason for the withdrawal (see enum below). |
| `assetParametersFiatTrustedDestination.memo` | Optional note to beneficiary, max 140 characters. If omitted, the memo on the trusted destination is used. |
### `purpose` values
`TRADING_SETTLEMENT` | `LENDING` | `INVESTMENT` | `EXPENSES` | `FEE_PAYMENT` | `GRANT_PAYMENT` | `PRIZE_AWARD` | `GIFT` | `REIMBURSEMENT` | `REBALANCE` | `INTRA_COMPANY`
### Response
A successful request returns `201` with a `withdrawalId`:
```json theme={null}
{
"data": {
"withdrawalId": "8696144cca28a634c05858d00e51191408498a7808a837fc4645b4b6997dde09"
}
}
```
## Managing bank trusted destinations
Listing fiat trusted destinations via API is supported. Creating, editing, and deleting them via API is in development. Add bank recipients in the web dashboard today by selecting **Fiat** as the destination type—see [Adding a USD trusted destination](/knowledge-base/platform/users/usd-banking#adding-a-usd-trusted-destination). For API details, see [Trusted destinations](/knowledge-base/platform/developers/move-money/setup/trusted-destinations).
# Network & gas fees
Source: https://docs.anchorage.com/knowledge-base/platform/developers/network-gas-fees
How blockchain transaction fees work and how Anchorage Digital manages them.
On blockchains, each node is incentivized to provide processing power to add a new block by the promise of collecting a reward. One such reward is a network fee — paid per transaction in the network's native currency by the address wishing to execute the transaction.
These fees serve an important role:
* Network fees help pay for network security by rewarding the people who keep track of activities across the network.
* Network fees incentivize purposeful use of the network. Free transactions would make it trivial to spam the network with meaningless activity, threatening its stability.
Fee calculation differs by blockchain — Anchorage Digital simplifies this by managing network fees on behalf of clients. On Ethereum, fees are called **gas fees**. On Bitcoin, they are simply called **transaction fees**.
For deeper background, see [Chapter 6 of the Bitcoin Whitepaper](https://bitcoin.org/bitcoin.pdf) and the [Gas and fees](https://ethereum.org/developers/docs/gas) article on Ethereum's website.
***
## Anchorage Digital fee requirements
For any blockchain interaction through Anchorage Digital:
* The wallet interacting with the blockchain must pay the transaction fees for that transaction.
* The wallet must hold enough balance to cover eventual transaction fees.
* Required balance is either:
* **Estimated** — for withdrawals, staking, and smart contract operations. Estimates are conservative to ensure sufficient funds remain at broadcast time.
* **Fixed** — referred to as the "Fee threshold" for transfers initiated through the API.
* The actual fee set at broadcast time is always based on a network fee estimate plus an overhedge.
***
## Transaction FeeThreshold (API only)
To ensure on-chain operations triggered by API have the highest probability of processing during times of high fees and market volatility, Anchorage Digital defines an internal `FeeThreshold` for each protocol.
This `FeeThreshold` is an internal "sufficient funds" check — not the actual fee charged. It ensures that when multiple transfers or operations are triggered from the same wallet, funds exist to process each transaction. Once this check passes, the transaction is processed on-chain and the actual fee is charged. If a transfer is queued, the transfer amount and `feeThreshold` are held and inaccessible to prevent double-spending.
If the wallet has insufficient funds, the API call returns an error.
The `FeeThreshold` is fixed and intentionally conservative. Actual fees at broadcast time may be higher or lower depending on network conditions. This does not apply to iOS or web operations.
***
## Gas limit
The **gas limit** specifies how many units of gas a user is willing to pay to get a transaction executed. Gas units represent the computational work required to execute the transaction — more complex interactions require more gas.
Examples:
* A simple ETH transfer requires exactly **21,000 gas units**.
* An ERC-20 transfer requires more.
* A smart contract swap requires substantially more.
Setting a gas limit below what's required causes the transaction to fail on-chain.
***
## Base fee
The **base fee** is set by the network to manage congestion. A transaction must offer at least the base fee to be eligible for inclusion in a block.
The base fee adjusts between blocks:
* Increases by **12.5%** if the previous block was more than half full.
* Decreases by **12.5%** if the previous block was below the threshold.
***
## Gas station
The Anchorage Digital gas station is a convenient option for covering gas fees on ETH and ERC-20 withdrawals and transfers.
The gas station is enabled at the organization level. If the toggle is not visible in your UI, contact your account executive for enablement.
Gas station use is optional per transfer, controlled by the `useGasStation` flag:
| `useGasStation` | Behavior |
| ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| `false` (default) | ETH deducted from the same address. Transfer fails if insufficient ETH. |
| `true` | An estimated gas fee is transferred into the address and used for the transfer. Unused ETH remains in your address. Gas used is billed monthly. |
# Permission groups
Source: https://docs.anchorage.com/knowledge-base/platform/developers/permission-groups
Create permission groups and select the global and vault-level permissions each API key needs.
A permission group is a reusable rule set that defines what actions an API key can perform, scoped to a single vault or across multiple vaults. An API key's capabilities come from the group assigned to it, not the key itself, so the group is where you decide what an integration can do.
By default, Anchorage Digital vaults don't allow API access. To enable it, an administrator either creates a permission group with the permissions each vault needs, or creates a key using the default read-only group.
Any activity related to permission groups requires quorum approval, so changes stay in the hands of your trusted admins.
Set up multiple permission groups and create as many API keys as you need under each group.
Updates to a permission group propagate to all of its API keys. Deleting a group invalidates every key within it.
Each organization starts with a default read-only permission group, which you can modify at any time.
**Permission group segregation**
Most clients create a permission group per team or end-user group, with one key for each. For example:
* Admin permission group — full permissions
* Operations — limited to reading balances and internal transfers
* Accounting — read only
## How to create a permission group
From the homepage, select **Developers**, then **API 2.0** to access Anchorage Digital APIs, then select **Create new group**.
Give the permission group a name and select the appropriate global and vault-level permissions.
Optionally add a comment, then select **Endorse** to create the group. Follow the prompts to submit biometric approval through the mobile app — quorum approval is required. After quorum is met, Anchorage Digital reviews the group for approval.
To edit or delete a permission group, select the three-dot menu next to the group details. Edits and deletions also require quorum approval.
## Permission levels
When you create a permission group, your selections determine which APIs the associated keys can call. There are two levels of vault permissions.
### Global permissions
Global permissions sit across all of your vaults, not just one. If a key has the global **Initiate withdrawals** permission, it can initiate a withdrawal from any of your vaults. Withdrawals still require quorum approval.
### Vault-level permissions
Vault-level permissions are specific to a single vault. If a key has vault-level **Internal Transfer** permissions, it can initiate a transfer only from that source vault, or the wallets within it.
### All-vaults
The all-vaults option lets all current and future vaults inherit a permission. Even if a vault changes names or moves to a different account, any key keeps the permission.
## Permissions reference
| Category | Permission | Description | Use case |
| :---------- | :-------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------ |
| Global | Initiate withdrawals | Initiate withdrawals to external destinations. All withdrawals require quorum approval through the Anchorage Digital mobile app. | |
| Global | Read sub-accounts | View read-only information for ledger subaccounts. | Wealth Management and ETF only |
| Global | Write sub-accounts | Write to the ledger to manage ledger subaccounts. | Wealth Management and ETF only |
| Global | Execute trades | All trade clients: execute RFQs. Wealth Management only: orders, WebSocket, and FIX trading. | Trading clients only. Requires the user to be an Authorized Trader. |
| Global | Read trades | Read all trades placed across trading accounts tied to your organization. | |
| Global | Read deposit attribution | Read all pending and completed deposit attributions. | |
| Global | Deposit attribution | Attribute deposits as known deposits or spam. | |
| Global | Configure webhooks | Configure and manage webhooks via REST API. | |
| Global | Onboarding | Onboard and manage Wealth Management end clients. | Wealth Management only |
| Global | Initiate staking and unstaking | Initiate staking and unstaking operations from wallets. | |
| Global | Manage trusted destinations | Create and manage trusted destinations. | |
| Global | Manage collateral packages | Read collateral management package information. | Collateral Management only |
| Global | Read statements | Read statements. | Wealth Management only |
| Vault-level | Read | Read balances and transactions for the wallets within this vault. | |
| Vault-level | Create address | Create wallets and addresses within a vault. | |
| Vault-level | Transfer funds — within Anchorage Digital | Transfer funds from that source vault. | |
| Vault-level | Transfer funds — outside of Anchorage Digital | Transfer funds from that source vault. | |
| Vault-level | Authorize settlements | Authorize Atlas settlement from that source vault. | Atlas clients only |
| Vault-level | Propose and accept settlements | Propose and accept Atlas settlement from that source vault. | Atlas clients only |
Each API requires a specific permission tied to the permission group, and to the key that belongs to it. Use this table to map the permission you select to the operations it unlocks.

Once your group is approved, [create an API key](/knowledge-base/platform/developers/api-keys) and assign it to the group.
# Signing requests
Source: https://docs.anchorage.com/knowledge-base/platform/developers/request-signing
Create Ed25519 signatures for sensitive Anchorage Digital API requests.
Certain Anchorage endpoints require an [Ed25519 signature](https://en.wikipedia.org/wiki/EdDSA#Ed25519) in the request headers alongside the API key.
Signatures are optional unless explicitly required, but are encouraged for all requests for maximum security. The `Api-Signature` is valid for 60 seconds.
## Signature input
Create the signature by concatenating these values:
```text theme={null}
timestamp + uppercase HTTP method + request path including query + request body
```
For requests without a body, omit the body from the signature input. For
requests with a JSON body, sign the **exact bytes sent over the wire** —
that is, `JSON.stringify(body)` with no extra whitespace. Any difference
(stray spaces, trailing newlines, key reordering) will produce a signature
the server rejects.
| Value | Notes |
| -------------- | ------------------------------------------------------------------------------------------ |
| `timestamp` | Seconds since the Unix Epoch in UTC. It must be within one minute of the API service time. |
| `method` | Uppercase HTTP method, such as `GET`, `POST`, or `DELETE`. |
| `request path` | Path and query string, such as `/v2/transfers?foo=bar&baz=bang`. |
| `body` | `JSON.stringify(body)` for requests that include one. Empty for `GET`. |
## Sign a request
```java theme={null}
package com.anchorage.api.client;
import okio.Buffer;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
import org.bouncycastle.crypto.CryptoException;
import org.bouncycastle.crypto.Signer;
import org.bouncycastle.crypto.params.Ed25519PrivateKeyParameters;
import org.bouncycastle.crypto.signers.Ed25519Signer;
import org.json.JSONObject;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
/**
* A sample java API client to connect to Anchorage API v2
*
* Required dependencies:
* org.json:json:20210307
* org.bouncycastle:bcpkix-jdk15on:1.69
* commons-codec:commons-codec:1.15
* com.squareup.okio:okio:1.9.0
*/
public class RestClientWithSigning {
private RestTemplate restTemplate;
public static void main(String[] args){
RestClientWithSigning api = new RestClientWithSigning();
api.init();
api.apiCall();
}
private void init(){
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
factory.setConnectTimeout(2000);
factory.setReadTimeout(2000);
restTemplate = new RestTemplate(factory);
}
private void apiCall() {
try {
String url = "https://api.anchorage-staging.com/v2/trading/quote";
String body = createRequestBody();
HttpEntity request = new HttpEntity<>(body, createHeaders("/v2/trading/quote", HttpMethod.POST, body));
ResponseEntity responseEntity = restTemplate.exchange(url, HttpMethod.POST, request, String.class);
if (responseEntity != null && HttpStatus.CREATED == responseEntity.getStatusCode()) {
System.out.println(String.format("Getting data from ( %s ) response: %s", url, responseEntity.getBody()));
}
} catch (Exception e) {
e.printStackTrace();
}
}
private String createRequestBody(){
JSONObject body = new JSONObject();
body.put("currency", "ETH");
body.put("quantity", "1.2");
body.put("side", "BUY");
body.put("tradingPair", "ETH-USD");
return body.toString();
}
private HttpHeaders createHeaders(String requestPath, HttpMethod httpmethod, String body) throws DecoderException, CryptoException {
String api_key = "your API Key";
String signing_key_hex = "Your signing key";
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.set("Api-Access-Key", api_key);
String timestamp = String.valueOf(Instant.now().getEpochSecond());
byte[] toSign = decodeMessage(timestamp, httpmethod, requestPath, body);
String signature = bc_sign(Hex.decodeHex(signing_key_hex), toSign);
headers.add("Api-Signature", signature);
headers.add("Api-Timestamp", timestamp);
return headers;
}
private byte[] decodeMessage(String timestamp, HttpMethod httpmethod, String url_path, String body){
Buffer buffer = new Buffer();
buffer.write(timestamp.getBytes(StandardCharsets.UTF_8))
.write(httpmethod.name().getBytes(StandardCharsets.UTF_8))
.write(url_path.getBytes(StandardCharsets.UTF_8))
.write(body.getBytes(StandardCharsets.UTF_8));
return buffer.readByteArray();
}
private String bc_sign(byte[] signing_key, byte[] toSign) throws CryptoException {
Ed25519PrivateKeyParameters privateKeyParameters = new Ed25519PrivateKeyParameters(signing_key);
Signer signer = new Ed25519Signer();
signer.init(true, privateKeyParameters);
signer.update(toSign, 0, toSign.length);
return Hex.encodeHexString(signer.generateSignature());
}
}
```
```csharp theme={null}
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using Sodium;
// Dependencies: Sodium.Core 1.3.1
// Replace privateKey, publicKey, and Api-Access-Key with your keys
namespace WebAPIClient
{
class Program
{
private static readonly HttpClient client = new HttpClient();
static async Task Main(string[] args)
{
await ProcessAnchorageAPISign();
}
private static async Task
```ruby theme={null}
require "ed25519"
require "net/http"
require "time"
def hex_to_bin(s)
[s].pack('H*')
end
def bin_to_hex(s)
s.unpack('H*').first
end
private_key_seed_hex = '0101010101010101010101010101010101010101010101010101010101010101'
public_key_hex = '8a88e3dd7409f195fd52db2d3cba5d72ca6709bf1d94121bf3748801b40f6f5c'
key_pair_hex = private_key_seed_hex + public_key_hex
key_pair = hex_to_bin(key_pair_hex)
signing_key = Ed25519::SigningKey.from_keypair(key_pair)
timestamp = '1577880000' # Time.now.to_i.to_s
req = Net::HTTP::Post.new('/v2/transfers?foo=bar&baz=bang')
req.body = '{"source": {"id": "1c920f4241b78a1d483a29f3c24b6c4c", "type": "VAULT"},
"assetType": "ETH", "destination": {"id": "55e89d4a644d736b01533a2ea9b32a20", "type": "VAULT"}, "amount": "1000.00000000"}'
signature = signing_key.sign(timestamp + req.method + req.path + req.body)
req['Api-Access-Key'] = 'YOUR_ACCESS_KEY'
req['Api-Timestamp'] = timestamp
req['Api-Signature'] = bin_to_hex(signature)
puts bin_to_hex(signature)
```
```python theme={null}
import time
import requests
from nacl import signing
class AnchorageAuth(requests.auth.AuthBase):
ACCESS_KEY_HEADER = "Api-Access-Key"
SIGNATURE_HEADER = "Api-Signature"
TIMESTAMP_HEADER = "Api-Timestamp"
def __init__(self, access_key: str, signing_key_seed: bytes):
self.access_key = access_key
self.signing_key = signing.SigningKey(signing_key_seed)
def __call__(self, request: requests.PreparedRequest):
request.headers[self.ACCESS_KEY_HEADER] = self.access_key
timestamp = str(int(time.time()))
method = request.method.upper() if request.method else "GET"
body = request.body or b""
if isinstance(body, str):
body = body.encode("utf-8")
message = b"".join([
timestamp.encode("utf-8"),
method.encode("utf-8"),
request.path_url.encode("utf-8"),
body,
])
request.headers[self.SIGNATURE_HEADER] = self.signing_key.sign(message).signature.hex()
request.headers[self.TIMESTAMP_HEADER] = timestamp
return request
```
```js theme={null}
const { sign } = require("@noble/ed25519");
const axios = require("axios");
class AnchorageClient {
constructor(accessKey, signingKeySeed) {
this.accessKey = accessKey;
this.signingKeySeed = signingKeySeed; // 32-byte hex seed
this.basePath = "https://api.anchorage-staging.com";
}
async sendSignedRequest(method, endpoint, body) {
const timestamp = Math.floor(Date.now() / 1000);
const serializedBody = body ? JSON.stringify(body) : "";
const signatureInput = `${timestamp}${method}${endpoint}${serializedBody}`;
const messageHex = Buffer.from(signatureInput, "utf8").toString("hex");
const signature = await sign(messageHex, this.signingKeySeed);
const signatureHex = Buffer.from(signature).toString("hex");
return axios({
method,
url: this.basePath + endpoint,
data: body,
headers: {
"Api-Access-Key": this.accessKey,
"Api-Signature": signatureHex,
"Api-Timestamp": String(timestamp),
"Content-Type": "application/json",
},
}).then((res) => res.data);
}
}
// Example: request and accept a quote
const client = new AnchorageClient("YOUR_ACCESS_KEY", "YOUR_SIGNING_KEY_SEED");
const quote = await client.sendSignedRequest("POST", "/v2/trading/quote", {
tradingPair: "BTC-USD",
quantity: "1",
currency: "BTC",
side: "BUY",
});
await client.sendSignedRequest("POST", "/v2/trading/quote/accept", {
quoteID: quote.data.quoteID,
side: "BUY",
allowedSlippage: "0.001",
});
```
`JSON.stringify(body)` produces the same compact bytes the server signs
against, so you don't need to pre-serialize the request manually. The live
signer above applies the same canonicalization to anything you paste into
the body field.
# Sandbox onboarding
Source: https://docs.anchorage.com/knowledge-base/platform/developers/sandbox/sandbox-onboarding
Onboard to the Anchorage Digital sandbox with the demo app, QR enrollment, and mock KYC.
The sandbox has its own onboarding flow, separate from production. To gain access, contact your primary Anchorage Digital representative. You'll need two things:
* The Anchorage Digital demo iOS app
* A QR code from Anchorage Digital for your sandbox account, provided via onboarding email or Slack
Use your legal name and email when completing sandbox KYC—all other information can be mock data. For production, you must submit real information.
## Onboarding steps
Open [testflight.apple.com/join/REwU8aQe](https://testflight.apple.com/join/REwU8aQe) on an iOS device and follow the TestFlight prompts to download the Anchorage Digital demo app. No TestFlight code is needed—the link configures access.
For security purposes, you never use a username or password to log in to Anchorage Digital systems. Instead, scan the one-time QR code provided by your client experience manager, tap **Accept**, and complete enrollment—including facial and voice recognition setup. Subsequent logins use Face ID.
You'll receive an email prompting you to complete the KYC form. Click **Open application** to fill out the browser-based form and submit it for review and approval.
Once approved by Anchorage Digital, log in to the iOS demo app, tap **Settings**, then **Web dashboard login**. Go to [clientdashboard.anchorage-staging.com/login](https://clientdashboard.anchorage-staging.com/login/), scan the displayed QR code with the app, and complete Face ID verification on your device.
## Adding new users to your sandbox
Adding sandbox users differs from production in one way: the new user needs the demo app, which is distributed by TestFlight invite.
1. Share the prospective user's name and email with your Anchorage Digital representative—they'll send that user a TestFlight invite.
2. In your iOS app, generate an enrollment QR code: tap **Settings**, then **Team**, then **Add new user**, and follow the on-screen instructions.
3. Share the QR code with the new user to scan once they've installed the demo app.
For the full role and vault-policy options in the add-user flow, see [Adding users](/knowledge-base/platform/users/adding-users).
# Sandbox overview
Source: https://docs.anchorage.com/knowledge-base/platform/developers/sandbox/sandbox-overview
Explore the Anchorage Digital sandbox environment for safe testing before going to production.
The Anchorage Digital sandbox is a dedicated environment for clients and partners to safely test and simulate platform capabilities without affecting live data or assets. Use it to understand workflows, permission structures, and system behavior across various scenarios before moving to production.
## Platforms and tools
Interact with digital assets using the Anchorage Digital mobile application.
Gain comprehensive control and visibility over assets through the web interface.
Use REST and WebSocket APIs for automated interactions.
## Resources
The sandbox provides access to the resources needed to set up and manage testing scenarios. You can create permission groups and API keys, which define access controls and ensure secure API interactions.
The sandbox mirrors the production environment's permission architecture, letting you learn how to manage organizational quorum policies and user roles before going live. For details, see [Permission groups](/knowledge-base/platform/developers/permission-groups) and [API keys](/knowledge-base/platform/developers/api-keys).
## API testing
Read-only APIs can be tested directly in the API Reference section of this portal. Write APIs require a [request signature](/knowledge-base/platform/developers/request-signing) before the request can be sent.
## Sandbox asset support
| Asset | Mainnet | Sandbox asset |
| :---------- | :------ | :------------------------------------ |
| Bitcoin | BTC | BTC\_T (Bitcoin Testnet) |
| Ethereum | ETH | ETHHOODI (Hoodi testnet) |
| Ethereum L2 | USDG | USDANCHOODI (ETH L2 on Hoodi testnet) |
| Solana | SOL | SOL\_TD (Devnet) |
If additional asset support is needed, contact your designated point of contact. Public testnet faucets are available online. If you do not have access to testnet funds, your point of contact can send assets if needed.
# Sandbox testing guide
Source: https://docs.anchorage.com/knowledge-base/platform/developers/sandbox/sandbox-testing-guide
Set up access, configure API keys, and fund your Anchorage Digital sandbox environment.
Follow these steps to get started testing in the Anchorage Digital sandbox.
Contact your dedicated sales or customer experience point of contact to request sandbox access.
Follow [Sandbox onboarding](/knowledge-base/platform/developers/sandbox/sandbox-onboarding) to install the demo app, enroll with your QR code, and complete sandbox KYC.
Open the Anchorage Digital sandbox iOS application. Once your onboarding application is approved, navigate to **Settings** → **Web Dashboard Login** to access the web dashboard.
| Environment | URL |
| :----------------------- | :---------------------------------------------------- |
| Sandbox web dashboard | `https://clientdashboard.anchorage-staging.com/login` |
| Production web dashboard | `https://anchoragelogin.com/login/` |
If your testing requires API keys, create a permission group and API key for the sandbox environment. See [Permission groups and API keys](/knowledge-base/platform/developers/permission-groups) for full instructions.
Verify your API key by calling the API key info endpoint. Choose one of the following options.
**Option 1: Developer portal**
Navigate to the [API Reference](/knowledge-base/api-reference/introduction), enter your sandbox API key in the **Api-Access-Key** header field, and send a request.
Only sandbox API keys work in the developer portal. Test production keys in your own secure local environment.
**Option 2: Local environment**
Call `GET https://api.anchorage-staging.com/v2/apikey` with your API key in the `Api-Access-Key` header.
```bash theme={null}
curl --request GET \
--url https://api.anchorage-staging.com/v2/apikey \
--header 'Api-Access-Key: {API KEY HERE}' \
--header 'accept: application/json'
```
```python theme={null}
import requests
url = "https://api.anchorage-staging.com/v2/apikey"
headers = {
"accept": "application/json",
"Api-Access-Key": "{API KEY HERE}"
}
response = requests.get(url, headers=headers)
print(response.text)
```
The sandbox supports the following testnet assets.
| Token | Sandbox asset |
| :------------------------------- | :------------ |
| Bitcoin (Testnet) | BTC\_T |
| Ethereum (Hoodi Testnet) | ETHHOODI |
| ERC-20 tokens (USDC, USDT, etc.) | USDANCHOODI |
| Solana (Devnet) | SOL\_TD |
| SPL tokens (Devnet) | — |
| BUIDL (Sepolia) | BUIDLSEP |
Mainnet addresses cannot be created in the sandbox environment.
Public testnet faucets are available online. Contact your point of contact if you need testnet funds sent directly.
Deposits from external faucets can take time and are not always delivered. If a deposit is received, you must attribute it via API or in the web dashboard — see [Receive digital assets](/knowledge-base/platform/developers/move-money/deposit/crypto).
## Testing with an AI assistant
You can also drive read and write API testing from an AI assistant connected to these docs. See [Build with AI](/knowledge-base/build-with-ai/overview) to connect your assistant and pick up LLM-ready docs and ready-made prompts.
# Setting up
Source: https://docs.anchorage.com/knowledge-base/platform/developers/setting-up
Set up the permission groups, keys, and signatures you need to call the Anchorage Digital API.
The Anchorage Digital API lets you automate custody, transfers, trading, and reporting while staying inside the same security model that protects your assets. Every request runs over HTTPS and is governed by the permission group you assign to a key, so you control exactly what each integration can do.
This section walks you through setup end to end: creating the permission groups and keys you need, and signing sensitive calls.
Prefer to build with an AI assistant? Connect these docs to your AI tool and start from ready-made prompts. See [Build with AI](/knowledge-base/build-with-ai/overview).
## What you can build
Generate reports, build financial dashboards, and view all digital assets in custody.
Download crypto and fiat balances, including all transactions, and store data for processing and reconciliation.
Trade and manage a full suite of financial services within the Anchorage Digital ecosystem.
Stay current on key activities by integrating with [webhooks](/knowledge-base/platform/developers/webhooks/webhooks-configure).
## Set up your access
Complete these steps in order. The first two require quorum approval, so plan for your approvers to be available.
Define which vaults a key can access and what operations it can perform.
Generate an access key and tie it to a permission group.
Add an Ed25519 signature to endpoints that require one.
Only administrators can create and manage API keys and permission groups.
Ready to make your first request? Follow [Send your first API call](/knowledge-base/api-reference/introduction#send-your-first-api-call).
# Convert stablecoins
Source: https://docs.anchorage.com/knowledge-base/platform/developers/stablecoins/convert
One endpoint handles mint, redeem, and bridge—the asset pair sets the direction.
Mint, redeem, and bridge all post to the same endpoint, `POST /v2/stablecoins/conversion`. The `sourceAssetType` and `destinationAssetType` you pass determine which operation runs. This page covers how the three differ and the fields they share; each operation has its own page with the full payload.
## The three operations
* **[Mint](/knowledge-base/platform/developers/stablecoins/convert/mint)** — Convert USD into a stablecoin.
* **[Redeem (burn)](/knowledge-base/platform/developers/stablecoins/convert/redeem)** — Convert a stablecoin back to USD.
* **[Bridge across chains](/knowledge-base/platform/developers/stablecoins/convert/bridge)** — Move a stablecoin between chains.
| Operation | `sourceAssetType` | `destinationAssetType` | Transaction types |
| :------------ | :------------------------ | :------------------------- | :------------------------------------------ |
| Mint | `USD` | `` | USD leg: `TRANSFER`; stablecoin leg: `MINT` |
| Redeem (burn) | `` | `USD` | USD leg: `BURN`; stablecoin leg: `DEPOSIT` |
| Bridge | `` on chain A | same stablecoin on chain B | `BURN` and `MINT` (one of each) |
## Shared request fields
Every conversion takes the same core fields, whatever the direction:
| Field | Description |
| :--------------------- | :---------------------------------------------------------------------------------------------------------- |
| `sourceAssetType` | Asset being converted from. |
| `sourceWalletId` | ID of the wallet being debited—retrieve via `GET /v2/vaults/{vaultId}`. |
| `destinationAssetType` | Asset being converted to—confirm via `GET /v2/asset-types`. |
| `destinationWalletId` | ID of the wallet being credited. |
| `amount` | Amount as a string. |
| `idempotencyKey` | Unique string ≤128 characters. Use a distinct key per conversion to prevent duplicate submissions on retry. |
Generate a fresh `idempotencyKey` (for example, a v4 UUID) for each conversion and reuse it only when retrying that same conversion. This makes an interrupted call safe to repeat without minting or burning twice.
## What you get back
A successful request returns `authorizationOperationId`, and the conversion enters `INITIATED` status pending endorsement approval. Follow it to completion with the history and transactions endpoints—see [Track conversion status](/knowledge-base/platform/developers/stablecoins/operate/track-status).
## Which to use
* **Mint** when you're issuing stablecoins from USD you hold at Anchorage Digital.
* **Redeem** when you're converting stablecoins back into spendable USD.
* **Bridge** when you need the same stablecoin on a different chain without leaving custody.
# Bridge across chains
Source: https://docs.anchorage.com/knowledge-base/platform/developers/stablecoins/convert/bridge
Move a stablecoin between chains.
Bridging moves the same stablecoin from one chain to another. For shared concepts and the common request fields, see [Convert stablecoins](/knowledge-base/platform/developers/stablecoins/convert). This page covers the bridge-specific payload and behavior.
`POST /v2/stablecoins/conversion` requires the `Convert Stablecoins` permission. See [Set up](/knowledge-base/platform/developers/stablecoins/setup).
## Request
Set `sourceAssetType` and `destinationAssetType` to the same stablecoin on different chains.
```json Example payload theme={null}
{
"destinationAssetType": "USDX_HOODI",
"destinationWalletId": "82936bb546cf1fc83955b6d9ca76ff16",
"idempotencyKey": "z763a50d-aa82-4ec7-b5a3-89ad0462d248",
"sourceAssetType": "USDX_BSC_T",
"sourceWalletId": "940afa950652ed4fdffceb73b2745d02",
"amount": "10"
}
```
| Field | Description |
| :--------------------------------------- | :-------------------------------------------------------------------------- |
| `sourceAssetType` | Stablecoin on the source chain. |
| `destinationAssetType` | Same stablecoin on the destination chain—confirm via `GET /v2/asset-types`. |
| `sourceWalletId` / `destinationWalletId` | Wallet IDs on each respective chain. |
| `idempotencyKey` | Unique string ≤128 characters. Use a distinct key per conversion. |
## Two legs, one record
A bridge produces **one** record in `/v2/stablecoins/history` (`operationType: BRIDGE`) but **two** transactions in `/v2/transactions`—a `BURN` on the source chain and a `MINT` on the destination chain. To inspect both legs, retrieve `sourceOperationId` and `destinationOperationId` from history, then look each up via `GET /v2/transactions/{transactionId}`.
## Monitor status
Query [conversion history](/knowledge-base/platform/developers/stablecoins/operate/track-status), or `GET /v2/transactions` with `types=MINT,BURN` to see both legs.
Confirm the chain-specific `assetType` for both legs via `GET /v2/asset-types` before bridging. Source and destination differ only by chain, so a wrong variant routes funds to the wrong network.
# Mint
Source: https://docs.anchorage.com/knowledge-base/platform/developers/stablecoins/convert/mint
Convert USD into a stablecoin.
Minting converts USD into a stablecoin. For shared concepts and the common request fields, see [Convert stablecoins](/knowledge-base/platform/developers/stablecoins/convert). This page covers the mint-specific payload and behavior.
`POST /v2/stablecoins/conversion` requires the `Convert Stablecoins` permission. See [Set up](/knowledge-base/platform/developers/stablecoins/setup).
## Request
Set `sourceAssetType` to USD and `destinationAssetType` to the stablecoin you want to mint.
```json Example payload theme={null}
{
"destinationAssetType": "USDX_HOODI",
"destinationWalletId": "82936bb546cf1fc83955b6d9ca76ff16",
"idempotencyKey": "z763a50d-aa82-4ec7-b5a3-89ad0462d248",
"sourceAssetType": "USD_R",
"sourceWalletId": "940afa950652ed4fdffceb73b2745d02",
"amount": "10"
}
```
| Field | Description |
| :--------------------- | :-------------------------------------------------------------------------------- |
| `amount` | USD amount as a string. |
| `sourceWalletId` | ID of the USD wallet being debited—retrieve via `GET /v2/vaults/{vaultId}`. |
| `destinationAssetType` | Stablecoin to mint (for example, `USDX_HOODI`)—confirm via `GET /v2/asset-types`. |
| `destinationWalletId` | ID of the destination stablecoin wallet. |
| `idempotencyKey` | Unique string ≤128 characters. Use a distinct key per conversion. |
## Response
A successful request returns `authorizationOperationId`. The conversion enters `INITIATED` status pending endorsement approval.
## Monitor status
Query [conversion history](/knowledge-base/platform/developers/stablecoins/operate/track-status), or `GET /v2/transactions` with `types=MINT`.
# Redeem (burn)
Source: https://docs.anchorage.com/knowledge-base/platform/developers/stablecoins/convert/redeem
Convert a stablecoin back to USD.
Redeeming burns a stablecoin and credits USD. For shared concepts and the common request fields, see [Convert stablecoins](/knowledge-base/platform/developers/stablecoins/convert). This page covers the redeem-specific payload and behavior.
`POST /v2/stablecoins/conversion` requires the `Convert Stablecoins` permission. See [Set up](/knowledge-base/platform/developers/stablecoins/setup).
## Request
Set `sourceAssetType` to the stablecoin you're redeeming and `destinationAssetType` to USD.
```json Example payload theme={null}
{
"destinationAssetType": "USD_R",
"destinationWalletId": "940afa950652ed4fdffceb73b2745d02",
"idempotencyKey": "z763a50d-aa82-4ec7-b5a3-89ad0462d248",
"sourceAssetType": "USDX_HOODI",
"sourceWalletId": "82936bb546cf1fc83955b6d9ca76ff16",
"amount": "10"
}
```
| Field | Description |
| :-------------------- | :---------------------------------------------------------------- |
| `amount` | Stablecoin amount as a string. |
| `sourceAssetType` | Stablecoin being redeemed. |
| `sourceWalletId` | ID of the source stablecoin wallet. |
| `destinationWalletId` | ID of the USD wallet being credited. |
| `idempotencyKey` | Unique string ≤128 characters. Use a distinct key per conversion. |
## Response
A successful request returns `authorizationOperationId`. The conversion enters `INITIATED` status pending endorsement approval.
## Monitor status
Query [conversion history](/knowledge-base/platform/developers/stablecoins/operate/track-status), or `GET /v2/transactions` with `types=BURN`.
# Operate
Source: https://docs.anchorage.com/knowledge-base/platform/developers/stablecoins/operate
Track stablecoin conversions and interpret their status.
Once a conversion is submitted, follow it to completion and interpret its status with two read endpoints.
## How to follow a conversion
* [`GET /v2/stablecoins/history`](https://developers.anchorage.com/reference/getstablecoinhistory) — One record per conversion, with status and pointers to the underlying transactions. `operationType` indicates the type of operation carried out.
* [`GET /v2/transactions`](https://developers.anchorage.com/reference/gettransactions) — The underlying ledger entries, filterable by `types`.
For query parameters, example responses, and pagination, see [Track conversion status](/knowledge-base/platform/developers/stablecoins/operate/track-status).
## Status values
| Status | Meaning |
| :---------- | :------------------------------------------------------------------------------------ |
| `INITIATED` | Awaiting endorsements. |
| `EXECUTING` | Approved, pending settlement. |
| `COMPLETED` | Conversion settled. |
| `FAILED` | Conversion did not complete. |
| `UNKNOWN` | Forward-compatibility fallback—handle gracefully rather than treating it as an error. |
`subStatus` is an optional qualifier on `status`. The only customer-observable value today is `REJECTED_BY_CUSTOMER`, paired with `status: FAILED`.
## Key terms
| Term | Definition |
| :--------------------------------------------- | :------------------------------------------------------------------------------------------------------------- |
| `authorizationOperationId` | Operation ID returned by `/v2/stablecoins/conversion`. Tracks endorsement and approval. |
| `issueRedeemId` | Unique identifier for the conversion as a whole. Stable across both legs of a bridge. |
| `operationType` | In `/v2/stablecoins/history`: `MINT`, `BURN`, or `BRIDGE`. |
| `sourceOperationId` / `destinationOperationId` | Nullable transaction IDs for each leg. Pass to `GET /v2/transactions/{transactionId}` for full ledger details. |
| `status` | `INITIATED`, `EXECUTING`, `COMPLETED`, `FAILED`, or `UNKNOWN`. |
| `subStatus` | Optional qualifier on `status`. Currently only `REJECTED_BY_CUSTOMER` (with `status: FAILED`). |
| `idempotencyKey` | Client-supplied string ≤128 characters on `/v2/stablecoins/conversion`. Use a distinct key per conversion. |
## Idempotency and retries
Provide an `idempotencyKey` per conversion so an interrupted call can be retried safely without double-minting or double-burning. For status codes, rate limits, and cursor pagination, see [Errors and pagination](/knowledge-base/api-reference/errors-pagination).
# Track conversion status
Source: https://docs.anchorage.com/knowledge-base/platform/developers/stablecoins/operate/track-status
Query conversion history and filter the transactions endpoint.
Follow conversions with two endpoints: `/v2/stablecoins/history` for one record per conversion, and `/v2/transactions` for the underlying ledger entries. For the status vocabulary and key terms, see [Operate](/knowledge-base/platform/developers/stablecoins/operate).
## Query conversion history
**`GET /v2/stablecoins/history`** — [Reference](https://developers.anchorage.com/reference/getstablecoinhistory)
Returns one record per conversion with status, asset types, wallet IDs, and pointers to the underlying transactions. Results are paginated, ordered newest first. Requires the `Convert Stablecoins` permission.
| Parameter | Description |
| :-------------- | :-------------------------------------------------------------------------------------------- |
| `limit` | 1–100, default 100. |
| `lastCreatedAt` | Pagination cursor—RFC3339 timestamp from `createdAt` of the last record on the previous page. |
```json Example response theme={null}
{
"data": [
{
"amount": "100.80",
"authorizationOperationId": "auth_op_01HX...",
"createdAt": "2026-05-01T22:51:00.082Z",
"destinationAssetTypeId": "PYUSD",
"destinationOperationId": "tx_01HX...",
"destinationWalletId": "wallet_01HX...",
"issueRedeemId": "ir_01HX...",
"operationType": "MINT",
"sourceAssetTypeId": "USD",
"sourceOperationId": "tx_01HX...",
"sourceWalletId": "wallet_01HX...",
"status": "EXECUTING",
"subStatus": null
}
],
"page": {
"next": ""
}
}
```
`page.next` is a fully formed URL for the next page, or `null` when exhausted. Alternatively, paginate manually with `lastCreatedAt` set to the `createdAt` of the last record from the prior page.
To drill into a specific transaction, pass `sourceOperationId` or `destinationOperationId` to `GET /v2/transactions/{transactionId}` for the blockchain hash, fee, and confirmation details.
## Filter the transactions endpoint
**`GET /v2/transactions`** — [Reference](https://developers.anchorage.com/reference/gettransactions)
```
GET /v2/transactions?types=MINT,BURN&walletId={stablecoinWalletId}&startDate=2026-05-01&endDate=2026-05-31&limit=100
```
| Parameter | Description |
| :---------------------- | :-------------------------------------------------------------------------------- |
| `types` | Comma-separated types. Stablecoin values: `MINT`, `BURN`, `DEPOSIT`, `TRANSFER`. |
| `walletId` | Filter to a specific wallet; omit for all wallets in the org. |
| `startDate` / `endDate` | Inclusive UTC date range, `YYYY-MM-DD`. Earliest valid `startDate`: `2017-01-01`. |
| `limit` | 1–100, default 25. |
| `afterId` | Pagination cursor from the prior response's `page.next`. |
## Changelog
### 2026-05-01
**Added:** `GET /v2/stablecoins/history`—query mints, burns, and bridges with status, asset, wallet, and pointers to the underlying transactions.
# Overview
Source: https://docs.anchorage.com/knowledge-base/platform/developers/stablecoins/overview
Mint, redeem, and bridge stablecoins through a single Anchorage Digital conversion endpoint.
Stablecoin conversions let you move value between USD and stablecoins, and move a stablecoin across chains, all through the same security model that governs the rest of your assets. Every conversion runs through one endpoint—the asset pair you choose sets the direction.
**Testing:** Examples use the staging host `https://api.anchorage-staging.com` and `"USD_R"` for USD-side legs. In production, use `https://api.anchorage.com` and `"USD"`.
## Start here
* **Mint** — Convert USD into a stablecoin. See [Mint](/knowledge-base/platform/developers/stablecoins/convert/mint).
* **Redeem (burn)** — Convert a stablecoin back to USD. See [Redeem](/knowledge-base/platform/developers/stablecoins/convert/redeem).
* **Bridge** — Move a stablecoin between chains. See [Bridge across chains](/knowledge-base/platform/developers/stablecoins/convert/bridge).
## The mental model
All three operations call the same endpoint, `POST /v2/stablecoins/conversion`. The `sourceAssetType` and `destinationAssetType` you pass set what happens:
* **Mint** converts USD into a stablecoin (`sourceAssetType: USD`, `destinationAssetType: `).
* **Redeem (burn)** converts a stablecoin back to USD (`sourceAssetType: `, `destinationAssetType: USD`).
* **Bridge** moves a stablecoin between chains—`sourceAssetType` and `destinationAssetType` are the same stablecoin on different chains (for example, `USDX_BSC_T` → `USDX_HOODI`). Internally, a bridge runs a burn on the source chain and a mint on the destination chain through a shared reserve.
| Operation | Direction | Transaction types |
| :------------ | :------------------------------------------ | :------------------------------------------ |
| Mint | USD → stablecoin | USD leg: `TRANSFER`; stablecoin leg: `MINT` |
| Redeem (burn) | stablecoin → USD | USD leg: `BURN`; stablecoin leg: `DEPOSIT` |
| Bridge | stablecoin (chain A) → stablecoin (chain B) | `BURN` and `MINT` (one of each) |
For the full comparison and the request fields they share, see [Convert stablecoins](/knowledge-base/platform/developers/stablecoins/convert).
## Action availability
| Action | API | Web platform |
| :----------------------------------------------------------------------------------------------- | :------------- | :------------- |
| [Mint](/knowledge-base/platform/developers/stablecoins/convert/mint) | Live | Live |
| [Redeem (burn)](/knowledge-base/platform/developers/stablecoins/convert/redeem) | Live | Live |
| [Bridge](/knowledge-base/platform/developers/stablecoins/convert/bridge) | Live | Live |
| [Query conversion history](/knowledge-base/platform/developers/stablecoins/operate/track-status) | Live | Live |
| Stablecoin swaps (`operationType: SWAP`) | In development | In development |
`/v2/stablecoins/history` may return records with `operationType: SWAP` once stablecoin swaps go live. Treat unknown `operationType` and `status` values as a forward-compatibility fallback, not an error.
## Before you convert: prerequisites
Identify the wallets and asset types involved, then confirm the API key has the right permission and authentication. See [Set up](/knowledge-base/platform/developers/stablecoins/setup).
Stablecoin conversion and history endpoints require only the `Api-Access-Key` header—no `Api-Signature` or `Api-Timestamp`.
## Related
* [Convert stablecoins](/knowledge-base/platform/developers/stablecoins/convert) — How mint, redeem, and bridge differ, and the request fields they share.
* [Track conversion status](/knowledge-base/platform/developers/stablecoins/operate/track-status) — Query conversion history and the transactions endpoint.
* [Client stablecoins guide](/knowledge-base/platform/users/stablecoins) — The web dashboard and iOS stablecoin experience.
# Set up
Source: https://docs.anchorage.com/knowledge-base/platform/developers/stablecoins/setup
Identify wallets and asset types, then configure the permission and authentication for stablecoin conversions.
Before making a conversion, identify the source and destination wallets and confirm the exact `assetType` strings you'll use. Then make sure your API key has the right permission and authentication.
## Identify wallets and asset types
* `GET /v2/vaults/{vaultId}` — Retrieve `walletId` values and balances for the vault holding the source funds.
* `GET /v2/asset-types` — Look up exact `assetType` strings, including chain-specific variants like `USDX_BSC_T`.
Confirm the exact chain-specific `assetType` for both legs before you bridge. The source and destination are the same stablecoin on different chains, so a wrong variant routes funds to the wrong network.
## Permission
The API key must have the `Convert Stablecoins` vault permission. Configure it via [Permission groups](/knowledge-base/platform/developers/permission-groups).
## Authentication
Stablecoin conversion and history endpoints require only the `Api-Access-Key` header. No `Api-Signature` or `Api-Timestamp` headers are needed.
This differs from most money-movement endpoints, which require an Ed25519 request signature. See [Request signing](/knowledge-base/platform/developers/request-signing) for the general signing model.
# Pectra staking
Source: https://docs.anchorage.com/knowledge-base/platform/developers/staking/eth-pectra-staking
# Overview
### Key concepts
* **New validator provisioning:** requires at least **32 ETH**.
* **Adding stake:** you can add any amount to an existing validator, as long as the added stake does **not** increase the total amount per validator to more than **2048 ETH**.
* **Pectra vs pre‑Pectra:** use `validatorType` to distinguish validator types while keeping requests backward compatible.
* **Go-live providers:** `FIGMENT`.
### Relevant endpoints
* **[Stake](https://developers.anchorage.com/reference/createstake):** `POST /v2/transactions/stake`
* **[Unstake](https://developers.anchorage.com/reference/createunstake):** `POST /v2/transactions/unstake`
* **[List transactions](https://developers.anchorage.com/reference/gettransactions):** `GET /v2/transactions`
* **[List wallet balances](https://developers.anchorage.com/reference/getwallets):** `GET /v2/wallets`, `GET /v2/vaults/{vaultId}/wallets`, `GET /v2/wallets/{walletId}`
* **[Get staking positions](https://developers.anchorage.com/reference/getwalletpositions):** `GET /v2/wallets/{walletId}/staking/positions`
***
# Workflows
### Stake (provision or add stake)
**Endpoint**
[POST /v2/transactions/stake](https://developers.anchorage.com/reference/createstake)
#### When to use which fields
* **Provision a new Pectra validator**
* Provide: `validatorType`, `stakingProvider`
* Omit: `stakingPositionId`
* **Add stake to an existing validator position**
* Provide: `stakingPositionId`, `amount`
* Omit: `validatorType`, `stakingProvider`
#### Request body additions
Add a `parameters` object to specify Pectra‑specific behavior.
#### Example: Provision a new Pectra validator
```json theme={null}
{
"source": {
"type": "WALLET",
"id": "1c920f4241b78a1d483a29f3c24b6c4c"
},
"amount": "32",
"assetType": "ETH",
"description": "Internal 9876543210",
"idempotentId": "9876543210",
"parameters": {
"validatorType": "0x02",
"stakingProvider": "FIGMENT"
}
}
```
#### Example: Add stake to an existing staking position
```json theme={null}
{
"source": {
"type": "WALLET",
"id": "1c920f4241b78a1d483a29f3c24b6c4c"
},
"amount": "35",
"assetType": "ETH",
"description": "Add stake to existing position",
"idempotentId": "9876543211",
"parameters": {
"stakingPositionId": "FuS3FPfJDKSNot99ECLXtp3rueq36hMNStJkPJwWodLh"
}
}
```
#### Response
A successful request returns **201 Created** with a transaction id.
***
### Unstake (partial or full)
**Endpoint**
`POST /v2/transactions/unstake`
#### Request rules
* `stakingPositionId` is required.
* For **partial unstake**, provide `amount` and set `isFullAmount` to `false`.
* For **full unstake**, set `isFullAmount` to `true`. (In this case, `amount` is optional and may be ignored.)
#### Example: Partial unstake
```json theme={null}
{
"source": {
"type": "WALLET",
"id": "1c920f4241b78a1d483a29f3c24b6c4c"
},
"amount": "5",
"assetType": "ETH",
"idempotentId": "123456789",
"isFullAmount": false,
"description": "Unstake 5 ETH",
"stakingPositionId": "FuS3FPfJDKSNot99ECLXtp3rueq36hMNStJkPJwWodLh"
}
```
#### Response
A successful request returns **201 Created** with a transaction id.
***
### Consolidate to Pectra validator
**Endpoint**
`POST /v2/transactions/consolidate-stake`
**Request rules**
* Enter *source* `walletId` and `assetType` in the request body. Use ETH in Production and ETHHOODI in staging
* You can consolidate across wallets and vaults but not across different validator providers (different `stakingProvider` values)
* You can consolidate from Pectra to Pectra validators and Non-Pectra to Pectra validators; you cannot consolidate to non-Pectra validators
**Example: Consolidate request**
```json theme={null}
{
"source": {
"type": "WALLET",
"id": "1c920f4241b78a1d483a29f3c24b6c4c"
},
"assetType": "ETH",
"description": "Consolidate Stake",
"idempotentId": "12838927347",
"sourceStakingPosition": "0xa1d1...",
"targetStakingPosition": "0x9647..."
}
```
**Response**
A successful request returns **201 Created** with a transaction id.
***
### List transactions
This endpoint retrieves a list of all transactions for an org (deposits, withdrawals, rewards).
**Endpoint**
[GET /v2/transactions](https://developers.anchorage.com/reference/gettransactions)
#### Rewards behavior
For rewards, this endpoint will continue to return:
* `DELEGATION_REWARD`
* `STAKING_REWARD`
***
### List wallet balances
This endpoint retrieves wallet balances for either a single wallet or all wallets in a vault.
**Endpoints**
* [List all wallets for all vaults](https://developers.anchorage.com/reference/getwallets)
#### Expected behavior
* The response includes a list of balance types per wallet.
* For Pectra, `stakedBalance` will include rewards that auto‑compound.
```json theme={null}
{
"data": {
"walletId": "3d293c0d64c703023692216e9b4f5280",
"walletName": "Bitcoin Mainnet - Wallet 1",
"depositAddress": {
"address": "2N19AcihQ1a4MxQW658UFHTioUNnMkiHPkw",
"addressId": "a33f83d96ca95cac000a344aa478a8b8",
"addressSignaturePayload": "7b225465787441646472657373223a22324e313941636968513161344d78515736353855464854696f554e6e4d6b6948506b77227d",
"signature": "1642000aa9cca8e8610981aefbdb204b361c9dca3fa067b88fdacfba7a0f620d721378a33f4bbadad3923e633a4d712646d1e8e314e9fcb4aa4102c0581f6503"
},
"assets": [
{
"assetType": "BTC",
"availableBalance": {
"quantity": "10.00000000",
"assetType": "BTC",
"currentPrice": "9751.01",
"currentUSDValue": "97510.1"
},
"totalBalance": {
"quantity": "10.45234733",
"assetType": "BTC",
"currentPrice": "9751.01",
"currentUSDValue": "101920.94"
},
"stakedBalance": {
"quantity": "32.00000000",
"assetType": "BTC",
"currentPrice": "9751.01",
"currentUSDValue": "312032.32"
},
"unclaimedBalance": {
"quantity": "0",
"assetType": "BTC",
"currentPrice": "9751.01",
"currentUSDValue": "0"
}
}
],
"vaultId": "1c920f4241b78a1d483a29f3c24b6c4c",
"vaultName": "Long Hold Vault",
"isDefault": true,
"isArchived": false,
"networkId": "BTC",
"type": "WALLET"
}
}
```
***
### Get staking positions
This endpoint retrieves the staking positions (stake accounts) associated with a wallet.
**Endpoint**
[Staking positions for a wallet](https://developers.anchorage.com/reference/getwalletpositions)
#### Expected behavior
* The response includes validator positions and the amount staked for each position
***
### Common pitfalls
* Do not include `validatorType` and `stakingProvider` when **adding stake** to an existing position.
* Ensure you include `stakingPositionId` when **adding stake** or **unstaking** from a specific position.
* Ensure validator total does not exceed **2048 ETH** after adding stake.
# Pre-Pectra staking
Source: https://docs.anchorage.com/knowledge-base/platform/developers/staking/eth-staking
# Overview
Anchorage Digital now supports ETH staking operations initiated via API.
### Key concepts
* **New validator provisioning:** requires at least **32 ETH**.
* **Pectra vs pre‑Pectra:** use `validatorType` to distinguish validator types.
* Unclaimed rewards are claimed and deposited back to your source wallet on a regular basis.
* The staked ETH validator public key is listed as the `stakingPositionId` in the staking positions endpoint.
### Relevant endpoints
* **[Stake](https://developers.anchorage.com/reference/createstake):** `POST /v2/transactions/stake`
* **[Unstake](https://developers.anchorage.com/reference/createunstake):** `POST /v2/transactions/unstake`
* **[List transactions](https://developers.anchorage.com/reference/gettransactions):** `GET /v2/transactions`
* **[List wallet balances](https://developers.anchorage.com/reference/getwallets):** `GET /v2/wallets`, `GET /v2/vaults/{vaultId}/wallets`, `GET /v2/wallets/{walletId}`
* **[Get staking positions](https://developers.anchorage.com/reference/getwalletpositions):** `GET /v2/wallets/{walletId}/staking/positions`
***
# Workflows
### Initiate staking operation
1. **Funding wallet**
1. Fund the wallet in increments of 32 ETH and ensure you have sufficient gas to cover the on-chain movement of funds. Only staking operations in multiples of 32 will be approved.
2. Current minimum gas requirement per staking operation = 0.03 ETH.
2. [**Create a stake request (API)**](https://developers.anchorage.com/reference/createstake)
1. Initiate ETH staking operation API from your ethereum source wallet.
2. e.g. 32 ETH + gas
1. For more information about API gas fee requirements - See [Network and gas fees](https://developers.anchorage.com/docs/network-gas-fees).
3. Identifying destination address.
1. This is the source wallet, which can be identified by hitting the [List wallets API](https://developers.anchorage.com/reference/getwallets) endpoint.
3. **Quorum approval**
4. **Anchorage Digital - Risk review**
5. **Anchorage Digital sends ETH to the validator**
1. Transaction Type = `OTHER`
1. Status = `PENDING` until confirmed staked balance.
2. This can take \~12 hours to provision the validator plus however long the [queue](https://www.validatorqueue.com/) is at that time to actually activate the staking validator.
6. **Assets successfully staked**
1. [Staking position for a wallet API](https://developers.anchorage.com/reference/getwalletpositions)
1. Status of the position will now reflect that it is `ACTIVE`.
2. [ List vaults](https://developers.anchorage.com/reference/getvaults) (See `assets` balances)
1. `stakedBalance`Your current staked position balance for a specific wallet.
2. `unclaimedBalance`The amount of unclaimed staking rewards. Unclaimed rewards are claimed and deposited back to your source wallet on a regular basis.
3. [List wallets](https://developers.anchorage.com/reference/getwallets) (See `assets` balances)
1. `stakedBalance`Your current staked position balance for a specific wallet.
2. `unclaimedBalance`The amount of unclaimed staking rewards. Unclaimed rewards are claimed and deposited back to your source wallet on a regular basis.
***
### View claimed and unclaimed rewards
1. [List staking position for a given wallet ID (API)](https://developers.anchorage.com/reference/getwalletpositions)
1. Staking rewards begin accruing as soon as the staking position is `ACTIVE`.
2. **Daily reward snapshot**
1. Staking rewards are updated daily after our daily snapshot process runs.
3. [**List staking rewards for a given walletId (API)**](https://developers.anchorage.com/reference/getwalletrewards)
1. The rewards will be in a state of `UNCLAIMED` until they are swept back to the source wallet.
2. Also view staked ETH and reward positions in vaults and wallet balances:
1. [ List Vaults](https://developers.anchorage.com/reference/getvaults)
* `stakedBalance`Your current staked position balance for a specific wallet.
* `unclaimedBalance`The amount of unclaimed staking rewards. Unclaimed rewards are claimed and deposited back to your source wallet on a regular basis.
2. [List wallets](https://developers.anchorage.com/reference/getwallets)
* `stakedBalance`Your current staked position balance for a specific wallet.
* `unclaimedBalance`The amount of unclaimed staking rewards. Unclaimed rewards are claimed and deposited back to your source wallet on a regular basis.
4. **Automatic staking rewards sweep to source wallet (Anchorage Digital)**
1. This will be listed as a `STAKING_REWARD` transaction when hitting our [List transactions API](https://developers.anchorage.com/reference/gettransactions). Once this occurs, these rewards will be updated to `CLAIMED`.
5. [**List transactions (API)**](https://developers.anchorage.com/reference/gettransactions)
1. Once the deposit of rewards hits the wallet, they will be reflected by a Transaction type of `STAKING_REWARD`.
***
### Initiate unstaking operation
1. [**Create an unstake request (API)**](https://developers.anchorage.com/reference/createunstake)
2. **Quorum approval**
3. **Anchorage Digital risk review**
4. **Unstake operation auccessfully Initiated**
1. Transaction type = `OTHER`
2. Status = `INPROGRESS`
1. Unstake operations take place in two major phases:
* Exit the active validator set: Once a request to "exit" has been made, the validator is added to the exit queue. If there are no other validators in the exit queue, this part will take \~35 minutes. If there are other validators in the exit queue, this part can take several days as a maximum of 2,000 validators can exit per day.
* Withdraw balance back to the execution layer: Once exited, a validator must wait a minimum of 27 hours to be considered eligible to be withdrawn. At this point, the ETH able to be withdrawn will be transferred in the next recurring withdrawal sweep. Given normal network behavior, you can expect full staking withdrawal to take about one week on average.
2. We broadcast the Unstake message as soon as it is approved. ETH stake unbonding time is determined by the protocol. It takes between 1-10 days for funds to return back into the wallet's available balance
3. Position will update to `Exited` once your unbonding or unstaking operation completes.
5. **Funds returned to source wallet**
1. All funds, including unclaimed rewards will land in the source wallet.
2. Transaction type = `OTHER`
3. Staking positions and rewards will return to 0.
***
### Consolidate Stake from Pre-Pectra to Pectra
See instructions on [ETH Pectra staking API page](https://developers.anchorage.com/docs/ethereum-pectra-staking-api)
Note: you may consolidate across wallets and vaults but not across different validator providers (e.g. do NOT consolidate a Figment validator to a BlockDaemon validator)
***
# API endpoints
Endpoint
Required permissions
Overview
Notes
[Create a stake request](https://developers.anchorage.com/reference/createstake)
Initiate staking and unstaking
Initiate a staking operation of 32+ ETH (increments of 32) via API. After this, you will need to complete an iOS-based quorum approval on the app and pass Anchorage Digital risk review before the funds are moved.
You will need sufficient wallet and gas balance to initiate the staking operation. For ETH, the Anchorage Digital gas minimum required balance is 0.03 ETH per API staking operation, however this will likely not all be used, as this is just a conservative buffer to ensure the transaction does not fail on-chain due to insufficient gas fees available.
[Create an unstake request](https://developers.anchorage.com/reference/createunstake)
Initiate staking and unstaking
Initiate an unstaking request, also to be confirmed via quorum approval and Anchorage risk review. Once this is completed, the unstaking request will be submitted.
The funds will be sent back to your `source` wallet.
`transactionType` for Staking Transactions:
1: Staking and unstaking operations: `transactionType` = `OTHER`
2: Staking rewards Received: `transactionType` = `STAKING_REWARD`
* *Note*\*: Stake and unstake will be updated from `OTHER` in the coming months to it's own unique transaction type.
* *Transaction Status*\*:
`SUCCESS` - This transaction has succeeded.\\
`NEEDS_APPROVAL` - This transaction has begun but is awaiting approval by members of the quorum.
`INPROGRESS` - This transaction is currently in progress.
`FAILURE` - This transaction has failed.
`REJECTED` - This transaction has been rejected.
`EXPIRED` - This transaction has expired due to lack of quorum approval within specified approval window.
[Staking rewards for a wallet](https://developers.anchorage.com/reference/getwalletrewards)
Read vault activity
Get staking rewards (in aggregate) for a specific source wallet.
**Reward Type**
`UNCLAIMED` Rewards that have accrued but have not yet been sent back to the Anchorage Digital source wallet.
`CLAIMED`These are the total claimed rewards for this wallet.
[Staking position for a wallet](https://developers.anchorage.com/reference/getwalletpositions)
Read vault activity
Each staking operation will result in a unique `StakingPositionId` with an `ACTIVE` staking status, once the staking operation is completed.
* \*Staking validator public key
\*\*
The `stakingPositionId`represents the ETH validator's unique public key for this operation.\\
**Status**
`PENDING` Positions will be in a pending state form when they are
`ACTIVE` Once the position is officially Staked, the position will reflect an ACTIVE state
`EXITED`
[Get vault by ID](https://developers.anchorage.com/reference/getvault)
Read vault activity
Get your staked balances within wallets for a specific vault
**Position Asset Balances**
`stakedBalance` Your current staked position balance for a specific wallet.
`unclaimedBalance`An amount of a unclaimed staking rewards. Unclaimed rewards are claimed and deposited back to your source wallet on a regular basis.
[List wallet by ID](https://developers.anchorage.com/reference/getwallet)
Read vault activity
Get details and staked balances for a specific wallet
**Position Asset Balances**
`stakedBalance` Your current staked position balance for a specific wallet.
`unclaimedBalance`An amount of a unclaimed staking rewards. Unclaimed rewards are claimed and deposited back to your source wallet on a regular basis.
***
### Additional metadata
You may provide a description with each staking operation, that will be visible within your organization in the Anchorage Digital iOS app.
***
### Unsuccessful staking request
A stake request may fail for any of the following reasons:
* An ongoing stake already exists.
* The specified asset does not exist.
* The specified amount exceeds the available funds for this asset (insufficient funds).
* The provided API key does not have permissions to initiate staking from this vault.
If the initiated stake is approved by the quorum, the transaction may fail for any of the following reasons:
* There are insufficient funds to pay the blockchain network fee at the time of this transaction.
* There is a failure on the blockchain.
# SOL
Source: https://docs.anchorage.com/knowledge-base/platform/developers/staking/sol-staking
# Overview
### Key concepts
* **Minimum stake:** 2 SOL.
* **Validator selection:** provide either a validator `address` or a `providerName`.
* Provide **one or the other**, not both.
* **Multiple stake requests:** staking multiple times to the same validator address will create multiple `stakingPositionId` values.
* **Unstake timing:** unstake requires about **one epoch (\~2–3 days)** to complete.
* **Collect timing and stake-account reserve:** to maximize rewards and avoid unexpected stake-account closure:
* Prefer waiting **1 epoch after an unstake completes** before collecting, *or*
* Leave a minimum reserve of **2,282,880 lamports (0.00228288 SOL)** in the `stakingPositionId` to prevent the stake account from being destroyed.
### Endpoint summary
* **[Stake](https://developers.anchorage.com/reference/createstake):** `POST /v2/transactions/stake`
* **[Unstake](https://developers.anchorage.com/reference/createunstake):** `POST /v2/transactions/unstake`
* **[Collect (SOL-specific)](https://developers.anchorage.com/reference/collectstaking):** `POST /v2/transactions/collect`
* **[Get staking positions](https://developers.anchorage.com/reference/getwalletpositions):** `GET /v2/wallets/{walletId}/staking/positions`
* **[Get staking rewards](https://developers.anchorage.com/reference/getwalletrewards):** `GET /v2/wallets/{walletId}/staking/rewards`
* **[List available validators](https://developers.anchorage.com/reference/getdelegationaddresses):** `GET /v2/delegation-addresses/{assetType}`
# Workflows
### Stake (Solana)
**Endpoint**
`POST /v2/transactions/stake`
#### Request rules
* `assetType` must be `"SOL"`.
* `amount` must be at least `"2"`.
* Include `parameters` with **either**:
* `address` (validator public identifier), **or**
* `providerName` (provider name)
#### Example: Stake using validator address
```json theme={null}
{
"source": {
"type": "WALLET",
"id": "1c920f4241b78a1d483a29f3c24b6c4c"
},
"amount": "5",
"assetType": "SOL",
"description": "Internal 9876543210",
"idempotentId": "9876543210",
"parameters": {
"address": "FuS3FPfJDKSNot99ECLXtp3rueq36hMNStJkPJwWodLh"
}
}
```
#### Example: Stake using provider name
```json theme={null}
{
"source": {
"type": "WALLET",
"id": "1c920f4241b78a1d483a29f3c24b6c4c"
},
"amount": "5",
"assetType": "SOL",
"description": "Internal 9876543210",
"idempotentId": "9876543211",
"parameters": {
"providerName": "figment"
}
}
```
#### Response
A successful request returns **201 Created** with a transaction id.
***
### Unstake (Solana)
**Endpoint**
`POST /v2/transactions/unstake`
#### Request rules
* `stakingPositionId` and `amount` are required.
* After the unstake completes (about \~1 epoch), funds are **inactive** but not yet available for use.
* Use the **Collect** endpoint (below) to move inactive SOL back to the wallet.
#### Example: Unstake
```json theme={null}
{
"source": {
"type": "WALLET",
"id": "1c920f4241b78a1d483a29f3c24b6c4c"
},
"amount": "5",
"assetType": "SOL",
"idempotentId": "123456789",
"description": "Unstake 5 SOL",
"stakingPositionId": "FuS3FPfJDKSNot99ECLXtp3rueq36hMNStJkPJwWodLh"
}
```
#### Response
A successful request returns **201 Created** with a transaction id.
***
### Collect (Solana-specific)
The collect action moves **inactive** SOL from a stake account back to the wallet's **available** balance.
**Endpoint**
`POST /v2/transactions/collect`
#### Request rules
* `stakingPositionId` is required.
* `amount` is required.
* `assetType` must be `"SOL"`.
#### Example: Collect
```json theme={null}
{
"stakingPositionId": "FuS3FPfJDKSNot99ECLXtp3rueq36hMNStJkPJwWodLh",
"amount": "2",
"assetType": "SOL"
}
```
#### Possible failure reasons
* **400 Invalid request**: unsupported `assetType`, not enough available balance.
* **404 Not found**: staking position not found.
### Get staking positions
This endpoint retrieves the staking positions (stake accounts) associated with a wallet.
**Endpoint**
`GET /v2/wallets/{walletId}/staking/positions`
#### Expected behavior
* Accepts `SOL` as a valid asset type to retrieve positions.
* Returns SOL staking positions, including `stakingPositionId` values.
### Get staking rewards
This endpoint is used to query rewards generated by staking and assigned to a wallet.
**Endpoint**
`GET /v2/wallets/{walletId}/staking/rewards`
#### Expected behavior
* Accepts `SOL` as a valid asset type.
* Includes `address` as an optional filtering argument.
### List available validators (delegation addresses)
A new endpoint is introduced to retrieve the list of available validators for delegation.
**Endpoint**
`GET /v2/delegation-addresses/{assetType}`
#### Request parameters
* `assetType`: must be `SOL` for Solana validators.
* `limit`: pagination size.
* `afterId`: pagination cursor.
#### Example request
`GET /v2/delegation-addresses/SOL?limit=10&afterId=XXXXXX`
#### Example response
```json theme={null}
{
"data": [
{
"address": "FuS3FPfJDKSNot99ECLXtp3rueq36hMNStJkPJwWodLh",
"ownerAddress": "",
"destination": "",
"name": "Delegator name",
"description": "some description",
"anchorageValidator": false
}
],
"page": {
"next": "XXXXXY"
}
}
```
### Common pitfalls
* For `POST /v2/transactions/stake`, provide **either** `parameters.address` **or** `parameters.providerName` (not both).
* Do not expect unstaked SOL to be immediately available. Plan for **epoch timing**, then call **collect**.
* If you want to keep the stake account alive (for rewards or operational reasons), leave the **minimum reserve** in the stake account when collecting.
# Overview
Source: https://docs.anchorage.com/knowledge-base/platform/developers/staking/staking-overview
# Getting started with staking API
To get started, ensure you have the correct [API permission group](/knowledge-base/platform/developers/permission-groups), API key, and a sufficiently funded wallet.
End-to-end staking via API is available for **ETH and SOL** only. Stake other assets in the iOS app or web dashboard.
1. **Create the API permission group - including the following permissions:**
1. Read vaults.
2. Initiate staking and unstaking,
2. **Quorum approval**
1. Admins must confirm operation via quorum on iOS device.
3. **Create an API key with staking permission group**
1. Once you've created your permission group, create an API key tied to this permission group to use for staking operations.
2. See [API permission groups and API keys](/knowledge-base/platform/developers/permission-groups)
# Cost basis via API
Source: https://docs.anchorage.com/knowledge-base/platform/developers/tax/cost-basis
Provide cost basis and acquisition dates for in-kind deposits via API.
When assets are deposited from an external source, Anchorage may not have the original acquisition details. If cost basis isn't provided, the system defaults to \$0, which may affect your reported gains/losses. This information ensures that tax lots and gains/loss calculations reflect accurate historical cost basis.
Cost basis information you provide may impact data reported on 1099-DA, for eligible US tax-paying entities. Anchorage Digital partners with a third-party tax reporting provider to support tax reporting, including 1099-DA, 1099-MISC, and 1099-INT.
Anchorage Digital does not provide financial, tax, or legal advice. Consult a qualified professional for guidance specific to your situation.
## Cost basis method (HIFO)
Anchorage Digital uses **HIFO (Highest-In, First-Out)** by default for cost basis accounting unless otherwise configured.
**Example (HIFO):**
| Purchase | Quantity | Price |
| ---------- | -------- | ------------ |
| Purchase 1 | 10 BTC | \$20,000/BTC |
| Purchase 2 | 20 BTC | \$22,000/BTC |
| Purchase 3 | 15 BTC | \$35,000/BTC |
If 25 BTC are sold, HIFO assumes:
* 15 BTC from Purchase 3 sold first (highest cost)
* Remaining 10 BTC from Purchase 2
Our tax reporting provider offers HIFO, LIFO, and FIFO. Contact Anchorage customer service to request a change in default cost basis methodology. Individual lot selection is not currently available.
## Default logic and validations
* If a deposit is missing user-provided cost basis, the system assigns a default of `0`. Provide cost basis promptly after deposits complete to avoid inaccurate reporting.
* Cost basis updates support up to **100 lots per transaction**.
* The acquisition date must be **on or before** the transfer/deposit date.
* Trades may have small rounding differences due to settlement precision. Your internal reconciliation should account for this.
## API workflow
Identify tax accounts your API credentials can access.
**GET** `/tax/accounts`
```json theme={null}
{
"accounts": [
{
"taxAccountId": "acc_123",
"name": "Example 123"
}
]
}
```
Retrieve deposit transactions for a given tax account. Filter by `hasCostBasis=false` to return only deposits missing user-provided cost basis.
**GET** `/tax/accounts/{taxAccountId}/transactions`
```json theme={null}
{
"data": [
{
"assetType": "BTC",
"externalId": "9be748be-d760-4d36-90f8-86b699c4e8bd",
"id": "9cd9f4d4-078b-4e44-a308-7662fec0f546",
"receivedAssets": [
{
"acquisitionDatetime": "2026-04-06T17:55:48.083Z",
"costBasis": "2500",
"quantity": "1.0"
}
],
"transactionTime": "2022-07-30T22:15:31.99999Z"
}
],
"page": {
"next": ""
}
}
```
Submit one or more lots whose total quantity matches the deposit quantity.
**PATCH** `/tax/accounts/{taxAccountId}/transactions/{transactionId}`
```json theme={null}
{
"lots": [
{
"quantity": "0.7500",
"costBasis": "15000.00",
"acquisitionDate": "2024-05-10T14:19:52.539Z"
},
{
"quantity": "0.5000",
"costBasis": "12000.00",
"acquisitionDate": "2023-11-02T14:19:52.539Z"
}
]
}
```
**Validation rules:**
* Total lot quantities must equal the transaction quantity
* Acquisition date must be on or before transfer date
* Maximum 100 lots per transaction
Re-fetch the transaction and verify `costBasis` is no longer `0` and lots were accepted as submitted.
## Operational guidance
* **Timing:** Update cost basis as soon as possible after an in-kind deposit so downstream reporting reflects accurate lots and gains/loss.
* **Source of truth:** Use your internal records (exchange statements, wallet history, or prior custodians' reports) to determine acquisition dates and basis.
* **Auditability:** Retain supporting documentation for the lot inputs used.
## Troubleshooting
Common causes of failures:
| Issue | Cause |
| ---------------- | -------------------------------------------- |
| Request rejected | Lot quantities don't sum to deposit quantity |
| Date error | Acquisition date is after the transfer date |
| Too many lots | More than 100 lots submitted |
| Asset mismatch | Lots don't match deposit asset type |
| Unknown asset | Asset type not recognized |
## Tax terminology
| Term | Overview |
| -------------------- | --------------------------------------------------------------------------------------- |
| Tax account | Top-level unit used in the API for tax reporting |
| Tax transaction | A tax-relevant event such as a deposit |
| Gains/loss | Difference between sale price and cost basis |
| Inventory | Total quantity and cost basis of a specific asset type, consisting of multiple tax lots |
| Tax lot | A specific group of units acquired at the same time and cost basis |
| Acquisition date | Date when an individual gains control of an asset |
| Cost basis | Value of an asset in USD at time of acquisition, used to calculate gains or losses |
| Cost basis method | Methodology used to compute gains/losses (e.g., HIFO, FIFO, LIFO) |
| Missing cost basis | Occurs when assets are transferred into Anchorage without original acquisition details |
| Holding period | Duration an asset is held before being sold |
| Realized gain/loss | Gains or losses from the sale or disposition of an asset |
| Unrealized gain/loss | Gains or losses from price fluctuation not yet realized through a sale |
# Overview
Source: https://docs.anchorage.com/knowledge-base/platform/developers/trading/overview
Trading entities, interfaces, trade types, and asset support at Anchorage Digital.
Trading at Anchorage Digital spans multiple interfaces, entities, trade types, and asset support. This guide simplifies the trading options so you have all the information needed to trade successfully.
Get in touch with the trading team 24/7: [trading@anchorage.com](mailto:trading@anchorage.com)
## Trading entities
| Entity | Notes |
| :------------------------------ | :-------------------------------- |
| **Anchorage Digital Hold** | Anchorage Digital agency desk. |
| **Anchorage Prime (legacy A1)** | Anchorage Digital principal desk. |
## Trade interfaces
| Interface | Notes |
| :---------------------------------- | :------------------------------------------------ |
| **Anchorage Digital web dashboard** | RFQ only |
| **Advanced trading (web only)** | |
| **REST API** | |
| **Websocket** | Restricted to wealth management clients |
| **FIX** | Restricted to wealth management clients |
| **Chat trading** | Outreach to Anchorage Digital trade desk required |
## Trading types
| Trade type | Web dashboard | Advanced trading | REST API | Websocket | FIX | Chat |
| :---------------- | :------------ | :--------------- | :-------- | :-------- | :-------- | :-------- |
| **RFQ** | | | | | | |
| **Market order** | | | | | | |
| **Limit FoK** | | | | | | |
| **Resting Limit** | | | | | | |
| **Limit GTC** | | | | | | |
| **Limit IOC** | | | | | | |
| **Stop-limit** | | | | | | |
| **Stop-loss** | | | | | | |
| **Take-profit** | | | | | | |
| **Algo. trading** | | | | | | |
## Asset support
Asset support varies by trade entity and interface. Reach out to your point of contact for the most recent asset support.
* [List supported trading pairs](https://developers.anchorage.com/reference/gettradepairs)
This is not comprehensive for all assets supported for chat trading at Anchorage Digital.
## Trade pre-funding
All trades are typically pre-funded to the Anchorage Digital trading desk. Work with your point of contact to receive pre-funding instructions.
## API keys — Authorized trader permission
Clients creating an API key with trade permissions must be an authorized trader on the account. If they are not, the **Execute trade** permission will not be visible.
# Quickstart
Source: https://docs.anchorage.com/knowledge-base/platform/developers/trading/quickstart
Step-by-step guide to understanding your trading account and completing your first trade.
This guide walks through understanding your trading account and completing your first trade.
This section assumes you have already created and configured your API key.
List the trading accounts associated with your organization to get the trading account ID(s) needed for future calls.
**GET** `/v2/trading/accounts`
```json theme={null}
{
"data": [
{
"enabled": true,
"id": "1a7df984-c4b4-11ef-ad6b-4e27db456598",
"name": "Test Trading Account [TRUST]"
}
]
}
```
Check the pre-funded balance using your API key and the trading account ID from the previous step.
**GET** `/v2/trading/accounts/{tradingAccountId}/balance`
```json theme={null}
{
"data": [
{
"balance": {
"assetType": "USD",
"currentPrice": "1",
"currentUSDValue": "989793.79",
"quantity": "989793.79"
}
},
{
"balance": {
"assetType": "BTC",
"currentPrice": "94404.709262226",
"currentUSDValue": "755237.67",
"quantity": "8"
}
},
{
"balance": {
"assetType": "SOL",
"currentPrice": "183.26165178161",
"currentUSDValue": "916.31",
"quantity": "5"
}
}
]
}
```
Check the credit limit for the account and any unsettled trades.
**GET** `/v2/trading/accounts/{tradingAccountId}/credit`
```json theme={null}
{
"data": {
"limits": [
{
"assetType": "USD",
"quantity": "1000000"
}
],
"usage": [
{
"assetType": "AAVE",
"quantity": "50"
},
{
"assetType": "USD",
"quantity": "100770.01"
}
]
}
}
```
Review available trading pairs for your organization.
**GET** `/v2/trading/pairs`
```json theme={null}
{
"data": [
{
"description": "Buy AAVE with USD, or Sell AAVE for USD",
"pair": "AAVE-USD",
"referenceData": {
"baseAssetType": "AAVE",
"baseSizeIncrement": "0.00000001",
"lastUpdateTime": "2024-07-09T15:57:55.249Z",
"minimumOrderSize": "0.000000010000000000000002",
"priceIncrement": "0.0000001",
"quoteAssetType": "USD",
"quoteSizeIncrement": "0.01"
}
},
{
"description": "Buy ATOM with USD, or Sell ATOM for USD",
"pair": "ATOM-USD",
"referenceData": {
"baseAssetType": "ATOM",
"baseSizeIncrement": "0.0001",
"lastUpdateTime": "2024-07-09T15:58:40.249Z",
"minimumOrderSize": "1",
"priceIncrement": "0.000001",
"quoteAssetType": "USD",
"quoteSizeIncrement": "0.001"
}
}
]
}
```
Request a quote with the following parameters:
| Parameter | Description | Example |
| :------------- | :----------------------------------- | :---------- |
| `tradingPair` | Pair from the prior call | `"BTC-USD"` |
| `quantity` | Quantity in currency units | `"1"` |
| `currency` | Currency of quantity | `"BTC"` |
| `side` | `"BUY"`, `"SELL"`, or `"TWOWAY"` | `"BUY"` |
| `idempotentId` | Unique per quote to avoid duplicates | UUID |
| `accountId` | Trading account ID | UUID |
**POST** `/v2/trading/quote`
```json theme={null}
{
"currency": "BTC",
"quantity": "1",
"side": "BUY",
"tradingPair": "BTC-USD",
"idempotentId": "01944c42-5ad3-4108-b376-f78cd6ff0394",
"accountId": "fd80d8fc-d20f-11ef-ab13-d2dbc7cc735e"
}
```
Response:
```json theme={null}
{
"data": {
"offerAmount": {
"assetType": "USD",
"quantity": "99551.67"
},
"offerPrice": "99551.67",
"quoteID": "45055f47-1d5c-4444-921c-7208c3e4178e",
"quoteRequest": {
"currency": "BTC",
"quantity": "1",
"side": "BUY",
"tradingPair": "BTC-USD"
},
"quoteStatus": "OPEN",
"timestamp": "2025-01-15T19:29:01.870Z",
"validUntilTime": "2025-01-15T19:29:04.870Z"
}
}
```
Accept the quote to execute the trade.
**POST** `/v2/trading/quote/accept`
```json theme={null}
{
"quoteID": "45055f47-1d5c-4444-921c-7208c3e4178e",
"side": "BUY",
"allowedSlippage": "0.001",
"accountId": "fd80d8fc-d20f-11ef-ab13-d2dbc7cc735e",
"idempotentId": "01944c42-5ad3-4108-b376-f78cd6ff0394"
}
```
Response:
```json theme={null}
{
"data": {
"quoteID": "45055f47-1d5c-4444-921c-7208c3e4178e",
"side": "BUY",
"tradeID": "4ececdba-56c9-4cf2-ae11-9f439c351b43",
"tradeStatus": "PENDING"
}
}
```
# Getting trading data
Source: https://docs.anchorage.com/knowledge-base/platform/developers/trading/read-apis
Understand your account configuration and retrieve order, trade, and settlement history.
## Account configuration
Once Anchorage enables and configures your trading account, use the following endpoints to confirm the configuration aligns with your expectations.
Your `tradingAccountId` is not the same as your `vaultId`, which is tied to a specific custody vault.
[List trading accounts](https://docs.anchorage.com/reference/gettradingaccounts) — provides enabled status, account ID, and name for each trading account associated with your organization. Anchorage typically opens a single trading account per legal entity.
[List trading account balances](https://docs.anchorage.com/reference/gettradingaccountbalance) — check the pre-funded balance for each trading account. Balances do not include outstanding trade activity.
[Get trading account credit and limit usage](https://docs.anchorage.com/reference/gettradingaccountcredit) — check the credit limit and current usage for a specific account. Usage only includes active unsettled trades.
When viewing pre-funded trading limits:
* **`creditLimitAmount`** — pre-funded trading balance at the start of the client's trading period, in USD. Does not change unless agreed upon with Anchorage Digital.
* **`creditSpendAmount`** (shown as "outstanding" on the web dashboard) — how much of the limit has been used. Updated after each trade based on outstanding positions.
[Get credit limit details](https://docs.anchorage.com/reference/gettradingaccountbalance) — check the credit limit applied to your organization. May differ from individual account limits and does not include usage.
[List supported trading pairs](https://docs.anchorage.com/reference/gettradepairs) — review pairs supported for your organization. Supported pairs vary by Anchorage entity (Anchorage Digital Bank, Anchorage Digital Singapore, A1).
### Account configuration endpoint reference
| Endpoint | Required permissions | Overview | Notes |
| :--------------------------------------------------------------------------------------------------------- | :------------------------------------ | :----------------------------------------------------- | :-------------------------------------------------------------------------------- |
| [List trading accounts](https://docs.anchorage.com/reference/gettradingaccounts) | Read trade activity | Account ID, name, and status for each trading account. | Must be created and enabled by Anchorage. Returns Forbidden if no account exists. |
| [Get trading account by ID](https://docs.anchorage.com/reference/gettradingaccount) | Read trade activity | Name, ID, and enabled status of a specific account. | |
| [List trading account balances](https://docs.anchorage.com/reference/gettradingaccountbalance) | Read trade activity | Pre-funded balances per trading account. | Does not include outstanding trade activity. |
| [Get trading account credit and limit usage](https://docs.anchorage.com/reference/gettradingaccountcredit) | Read trade activity | Credit limit and current usage for a specific account. | Credit accounts only. Usage reflects outstanding trades only. |
| [Get credit limit details (org level)](https://docs.anchorage.com/reference/gettradingaccountbalance) | Read trade activity | Credit limit at the organization level. | Credit accounts only. Does not include usage. |
| [List supported trading pairs](https://docs.anchorage.com/reference/gettradepairs) | Execute trades or Read trade activity | Supported pairs for the organization. | |
***
## Order, trade, and settlement history
Most history and status requests can be made with either "Read trade activity" or "Execute trades" permissions. With only "Execute trades", you will only receive orders, trades, and settlements available to that API key.
### List activity
| Endpoint | Description |
| :-------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------- |
| [List orders](https://docs.anchorage.com/reference/getordersstatus) | All orders placed. Accepted RFQ quotes are not considered orders and will not appear here. |
| [List trades](https://docs.anchorage.com/reference/gettrades) | All trades with ID, status, and details. Filterable by date, status, trading account, and pair. |
| [List outstanding trades](https://docs.anchorage.com/reference/gettradingpositions) | Filtered view of list trades showing only outstanding trades. |
| [List settlements](https://docs.anchorage.com/reference/getsettlements) | All settlements with settlement ID and details. |
| [List trades by settlement](https://docs.anchorage.com/reference/gettradesbysettlement) | Underlying trades for a given settlement ID. |
### Get by ID
[**Get order by ID**](https://docs.anchorage.com/reference/getorderstatus)
| Status | Explanation |
| :--------------- | :------------------------------------------------------------ |
| Pending | Order is queued and awaiting processing. |
| New | Order has been accepted and is active. |
| Partially filled | Order has been partially executed but not completely filled. |
| Filled | Order has been fully executed. |
| Rejected | Order was not accepted due to an error or invalid parameters. |
| Pending cancel | Cancellation request submitted but not yet confirmed. |
| Canceled | Order has been canceled and is no longer active. |
[**Get trade by ID**](https://docs.anchorage.com/reference/gettrade)
| Status | Explanation |
| :------- | :--------------------------------------------------------------------------------------------------- |
| Pending | Quote accepted. Temporary status updated once Anchorage receives full trade info from market makers. |
| Executed | Filled price and fees are available. Trade updated before settlement is created. |
| Settling | Client has sent netted owed balances to Anchorage Digital. |
| Settled | Anchorage Digital has sent its netted owed balances to the client. |
| Rejected | Trade failed, likely due to asset volatility outside slippage or insufficient pre-funded limit. |
| Canceled | Trade was manually canceled. |
[**Get settlement by ID**](https://docs.anchorage.com/reference/getsettlement)
| Status | Explanation |
| :------- | :-------------------------------------------------------------------------- |
| Pending | Settlement has been created. |
| Settling | Settlement in progress; owed funds are being sent. |
| Settled | Anchorage Digital has sent its netted owed balances. Terminal state. |
| Canceled | Settlement was manually canceled. Terminal state. |
| Executed | Deprecated status. Expect either `EXECUTED` or `PENDING` during transition. |
# Quote & placing orders
Source: https://docs.anchorage.com/knowledge-base/platform/developers/trading/rfq-orders
Execute trades via request-for-quote or limit/market orders using the REST API and WebSocket.
There are two methods to execute a trade using Anchorage's standard APIs:
1. **RFQ (Request for Quote)** — provides a market price for a trading pair and size; the user accepts before expiry to execute.
2. **Market or limit orders** — submitted directly; filled when relevant conditions are met.
***
## Request and accept a quote
The [Request quote](https://developers.anchorage.com/reference/requestquote) endpoint provides a market price for a given trading pair, side, and amount. The response includes the asset type, quantity, quote details, a `quoteID`, and a validity window — **typically around 3 seconds**. Anchorage does not maintain a history of offered quotes.
RFQs support `BUY`, `SELL`, and `TWOWAY` trades. `TWOWAY` allows buying one asset and selling another in a single trade.
To execute, [accept the quote](https://developers.anchorage.com/reference/acceptquote) by providing the `quoteID`, trade side, trading account, and `idempotentId` (if used in the RFQ) **within the 3-second offer window**. The trade executes immediately upon acceptance.
### Avoid duplicate trades with idempotentId
The RFQ request does not require `idempotentId`, but it is strongly recommended to prevent duplicate trades.
When a unique `idempotentId` is included in a quote request, Anchorage will not allow acceptance without the same ID in the accept request. Submitting an accept with a prior `idempotentId` returns the trade info from that previous trade — no new trade is created.
### Allowed slippage
The `allowedSlippage` parameter on accept sets the maximum slippage Anchorage Digital will tolerate, expressed as actual value (e.g., `"0.001"` = 10 bps). Must be between `0` and `0.002` (20 bps). Trades exceeding 20 bps slippage are rejected.
**Example:**
Quote price: \$10,000 | `allowedSlippage`: `"0.0008"` (8 bps)
| Scenario | Outcome |
| :--------------------------------------------------- | :----------------------------------- |
| Market moves against quote but stays within slippage | Filled — price at \$10,007 or better |
| Market exceeds quote price + slippage | Rejected |
Commission (trading bps) is included in the quoted price and is independent of slippage.
### Trade confirmation
Trade summary details are returned immediately, but there may be a short delay before completed price and fee information is available. The actual trade amount will never work against the client — only in the client's favor, if it changes at all.
This occurs because Anchorage Digital routes through an OMS for superior price execution across market makers and exchanges. The OMS synchronizes multiple exchange update methods (API, webhooks, etc.) on differing time frames, which can cause a slight delay between quote acceptance and full trade details.
***
## Place an order
The place-an-order endpoints are applicable for users with separate ledgers (e.g., RIAs). RIAs should refer to the dedicated [RIA integration documentation](https://developers.anchorage.com/docs/key-product-information-copy) for more detail.
### REST API
The [Place an order](https://developers.anchorage.com/reference/newordersingle) endpoint supports limit Fill-or-Kill (FoK) orders — if conditions cannot be met immediately, the order is canceled and no trade occurs.
**Limit price:** Include a limit price to account for market movement between placement and execution. This protects the trader and ensures sufficient funds are allocated.
### WebSocket API
WebSocket uses a bidirectional JSON protocol, enabling real-time market data. Once authenticated, use the [NewOrderSingle](https://developers.anchorage.com/docs/websocket-api-submit-order) message to submit orders and receive execution reports over the same session.
Supported order types: `MARKET` and `LIMIT`.
Refer to the [WebSocket API Getting Started guide](https://developers.anchorage.com/docs/websocket-api-getting-started) for a detailed walkthrough.
# Settlement process
Source: https://docs.anchorage.com/knowledge-base/platform/developers/trading/settlement
How trades settle at Anchorage Digital, including pre-funded and credit limit settlement flows.
Trades remain in `EXECUTED` status until settlement is triggered. Anchorage Digital then creates an official settlement calculation by account — netting all outstanding positions and providing instructions on how to settle. Settlement details are available in the web dashboard under the **Trade** tab and via the [settlement APIs](https://docs.anchorage.com/reference/getsettlements).
Settlement is netted by account and asset for crypto; fiat is netted by trading account. Each settlement instructs the client on the quantity and destination to send assets and fiat.
Clients can designate the exact vault, wallet, or address where Anchorage Digital trading should deposit funds. This destination can be adjusted at any time.
***
## Pre-funded trading settlement
The sell-side of each trade is automatically removed from the client's pre-funded balance when a trade executes. Anchorage Digital deposits the buy-side asset into the trading account once the trade fully settles. Assets are not automatically returned to the client's custody account unless requested.
***
## Credit limit trading settlement
Anchorage Digital does not automatically pull fiat or assets from the client's vault. Clients must initiate transfers manually via one of:
* **Create transfer / withdrawal request** endpoint
* **Anchorage Digital web dashboard** withdraw operation
* **Atlas**
The destination deposit address for each transfer is provided by Anchorage Digital via API. Separate transfers are required per asset.
For account-based assets in a single wallet, network fees are paid in the underlying native asset — e.g., USDC settlement fees are paid in ETH from the same wallet. Ensure sufficient gas ahead of settlement.
Refer to the [Network fees](https://developers.anchorage.com/docs/network-gas-fees) page for details on how Anchorage Digital can support network fees. Pre-funded trading limits are updated based on remaining balances at the start of each trading period.
***
## Netted settlement
### Net buy and net sell
| Scenario | Definition |
| :----------- | :--------------------------------------------------------------------- |
| **Net buy** | Client purchased more of an asset than sold during the trading session |
| **Net sell** | Client sold more of an asset than purchased during the trading session |
### Multi-asset settlement example
If a client has a **net sell** in BTC and executes a **new buy** for ETH within the same session:
Initiate an internal transfer from the client's wallet or vault to Anchorage Digital's settlement vault.
Initiate a fiat transfer from the client's bank to Anchorage Digital's fiat account (to cover the ETH buy).
Once crypto and fiat are received and confirmed, Anchorage Digital transfers ETH into the assigned client account, completing settlement.
# Authentication
Source: https://docs.anchorage.com/knowledge-base/platform/developers/trading/websocket-authentication
Authenticate WebSocket connections using API keys and Ed25519 signatures.
## Signing a request
To initiate a WebSocket connection to Anchorage Digital, the initial connection request header must be authenticated by including your API access key in the `Api-Access-Key` header and by providing an Ed25519 signature specifying the `Api-Signature` and `Api-Timestamp` headers. To register an API key for websocket trading, follow the [Setup guide](/knowledge-base/api-reference/introduction#send-your-first-api-call) and assign the **Execute trades (TRADE)** permission to your API key.
Code example for creating and signing a request header:
```python theme={null}
from nacl import signing
import requests
def signed_request(request: requests.PreparedRequest, api_access_key, api_signing_key):
timestamp = timestamp = str(int(time.time()))
message = b"".join(
[bytearray(timestamp, "utf-8"), bytearray(request.method, "utf-8"),
bytearray(request.path_url, "utf-8"), request.body]
)
signing_key = signing.SigningKey(api_signing_key)
signature = signing_key.sign(message).signature.hex()
request.headers["Api-Access-Key"] = api_access_key
request.headers["Api-Signature"] = signature
request.headers["Api-Timestamp"] = timestamp
return request
```
# Getting started
Source: https://docs.anchorage.com/knowledge-base/platform/developers/trading/websocket-getting-started
Connect to the Anchorage Digital WebSocket API for real-time market data.
The Anchorage Digital WebSocket API supports the WebSocket protocol for real-time market data.
**Endpoint:** `wss://api.anchorage.com/ws/v2/trading`
## Protocol
This WebSocket API uses a bidirectional protocol that encodes all messages as JSON objects. Each message includes a `messageType` attribute for handling message types appropriately.
## Subscribe
Send a subscribe message with the appropriate `messageType` to specify which channel you want to receive.
### Customer-specific market data
Subscribes to market data scoped to a specific account or subaccount by passing either the optional `accountId` or `subaccountId` field.
**By account:**
```json theme={null}
{
"messageType": "MarketDataSnapshotRequest",
"timestamp": "2023-01-24T08:22:18.598364",
"payload": {
"type": "subscribe",
"symbol": "BTC-USD",
"reqId": "0d921bca-6599-4841-95ee-7b6984e2486f",
"accountId": "f7823b57-aeb2-11f0-a565-3ecdccd5480d"
}
}
```
**By subaccount:**
```json theme={null}
{
"messageType": "MarketDataSnapshotRequest",
"timestamp": "2023-01-24T08:22:18.598364",
"payload": {
"type": "subscribe",
"symbol": "BTC-USD",
"reqId": "0d921bca-6599-4841-95ee-7b6984e2486f",
"subaccountId": "5db3bae2-c3c6-4d7d-97af-47c923135661"
}
}
```
| Field | Type | Required | Description |
| -------------- | ------------- | --------- | --------------------------------------------------------------------------------------------- |
| `symbol` | string | | Trading pair, e.g. `BTC-USD` |
| `reqId` | string (UUID) | | Unique request ID for this subscription |
| `accountId` | string (UUID) | | Scopes the feed to a specific account. Use either `accountId` or `subaccountId`, not both. |
| `subaccountId` | string (UUID) | | Scopes the feed to a specific subaccount. Use either `accountId` or `subaccountId`, not both. |
`subaccountId` applies to RIA customers only.
### Global market data
Subscribes to market data without any account filter. All participants receive the same feed.
```json theme={null}
{
"messageType": "MarketDataSnapshotRequest",
"timestamp": "2023-01-24T08:22:18.598364",
"payload": {
"type": "subscribe",
"symbol": "BTC-USD",
"reqId": "0d921bca-6599-4841-95ee-7b6984e2486f"
}
}
```
## Unsubscribe
To unsubscribe from a channel, send an unsubscribe message with the same `symbol`. The `reqId` does not need to match the original subscription request.
```json theme={null}
{
"messageType": "MarketDataSnapshotRequest",
"timestamp": "2023-01-24T09:04:57.146353",
"payload": {
"type": "unsubscribe",
"symbol": "BTC-USD",
"reqId": "88f401f3-f0d1-4f1d-85cc-3d0b377e8c9a"
}
}
```
## Sequence numbers
Messages include a sequence number: an incrementing integer starting at `1`. Each message is exactly one greater than the previous.
## Supported channels
| Channel | Description |
| ------------------------- | -------------------- |
| MarketDataSnapshotRequest | Market depth updates |
# Market data
Source: https://docs.anchorage.com/knowledge-base/platform/developers/trading/websocket-market-data
Subscribe to real-time market depth updates via MarketDataSnapshotRequest.
## MarketDataSnapshotRequest
`MarketDataSnapshotRequest` subscribes to real-time market depth updates for a specified trading symbol.
Code example for subscribing to market data:
```python theme={null}
def subscribe_marketdata(ws, symbol, receiver, accountId=None, subaccountId=None):
payload = {
"type": "subscribe",
"symbol": symbol,
"reqId": str(uuid.uuid4())
}
if accountId is not None:
payload["accountId"] = accountId
if subaccountId is not None:
payload["subaccountId"] = subaccountId
msg = json.dumps({
"messageType": "MarketDataSnapshotRequest",
"timestamp": datetime.now().isoformat(),
"payload": payload
})
ws.send(msg)
while True:
resp = json.loads(ws.recv())
receiver(resp)
```
**Subscription example — BTC-USD:**
```json theme={null}
{
"messageType": "MarketDataSnapshotRequest",
"timestamp": "2023-02-08T14:19:43.901696",
"payload": {
"type": "subscribe",
"symbol": "BTC-USD",
"reqId": "e07b9683-af27-481a-b4db-1c492114e930"
}
}
```
**Example response:**
```json theme={null}
{
"messageType": "MarketDataSnapshot",
"timestamp": "2023-02-08T14:19:44Z",
"version": "1.0",
"seqNum": 9,
"sessionId": "fcd5d616-8208-401a-9001-d299bcc9a8c6",
"payload": {
"asks": [
{ "price": "23083.25076763", "size": "1" },
{ "price": "23084.28705625", "size": "4" },
{ "price": "23084.78", "size": "5" },
{ "price": "23089.14", "size": "40" },
{ "price": "23094.57", "size": "50" }
],
"bids": [
{ "price": "23081.96", "size": "1" },
{ "price": "23080.96918517", "size": "4" },
{ "price": "23080.61566563", "size": "5" },
{ "price": "23074.06841953", "size": "40" },
{ "price": "23068.87", "size": "50" }
],
"reqId": "e07b9683-af27-481a-b4db-1c492114e930",
"symbol": "BTC-USD"
}
}
```
***
### Subscription parameters
| Parameter | Type | Required | Description |
| -------------- | ------------- | --------- | --------------------------------------------------------------------------------------------- |
| `messageType` | string | | `"MarketDataSnapshotRequest"` |
| `symbol` | string | | Trading pair to subscribe to, e.g. `BTC-USD` |
| `reqId` | string (UUID) | | Unique request ID for this subscription |
| `accountId` | string (UUID) | | Scopes the feed to a specific account. Use either `accountId` or `subaccountId`, not both. |
| `subaccountId` | string (UUID) | | Scopes the feed to a specific subaccount. Use either `accountId` or `subaccountId`, not both. |
***
### Response parameters
| Parameter | Type | Required | Description |
| ------------- | --------- | --------- | --------------------------------------------------------- |
| `messageType` | string | | Identifies the message as a market data snapshot response |
| `symbol` | string | | Trading pair for this snapshot, e.g. `BTC-USD` |
| `asks` | object\[] | | Full list of asks |
| ⤷ `price` | string | | Limit price of the level |
| ⤷ `size` | string | | Size of this level |
| `bids` | object\[] | | Full list of bids |
| ⤷ `price` | string | | Limit price of the level |
| ⤷ `size` | string | | Size of this level |
# Submitting orders
Source: https://docs.anchorage.com/knowledge-base/platform/developers/trading/websocket-submit-order
Submit, cancel, and resend orders over a WebSocket session.
## NewOrderSingle
A `NewOrderSingle` message allows a user to submit an order and receive execution reports over the same WebSocket session. Currently `MARKET` and `LIMIT` order types are supported.
**Example request:**
```json theme={null}
{
"messageType": "NewOrderSingle",
"timestamp": "2023-03-12T22:22:09.925952Z",
"payload": {
"clOrderId": "47ce2580-5e57-45d8-b67f-71a5aa55d05f",
"symbol": "BTC-USD",
"side": "SELL",
"currency": "USD",
"quantity": "10000",
"orderType": "LIMIT",
"limitPrice": "21000",
"timeInForce": "GTC",
"accountId": "3fa8372d-b51d-44ab-a456-43e947e4be10"
}
}
```
**Example response:**
```json theme={null}
{
"messageType": "ExecutionReport",
"timestamp": "2023-03-12T22:22:09.925952Z",
"version": "1.0",
"seqNum": 3,
"payload": {
"clOrderId": "47ce2580-5e57-45d8-b67f-71a5aa55d05f",
"orderId": "99b60f12-a20c-4977-99ea-f9affdb8e5f2",
"accountId": "3fa8372d-b51d-44ab-a456-43e947e4be10",
"symbol": "BTC-USD",
"orderQty": "10000",
"side": "SELL",
"currency": "USD",
"orderType": "LIMIT",
"limitPrice": "21000",
"timeInForce": "GTC",
"orderStatus": "FILLED",
"execId": "58fd5afc-b85e-45d1-951e-d6429ea9cd54",
"execType": "FILL",
"avgPx": "21990.01",
"avgPxAllIn": "21968.02",
"cumQty": "10000",
"fillPx": "21990.01",
"fillQty": "10000",
"leavesQty": "0",
"cancelQty": "0",
"fee": "0.00045521",
"feeCurrency": "BTC",
"submitTime": "2023-03-12T22:22:09.909251Z",
"transactTime": "2023-03-12T22:22:09.925050Z"
}
}
```
**Example reject response:**
```json theme={null}
{
"messageType": "ExecutionReport",
"timestamp": "2023-03-12T22:22:09.925952Z",
"version": "1.0",
"seqNum": 5,
"payload": {
"clOrderId": "47ce2580-5e57-45d8-b67f-71a5aa55d05f",
"orderId": "99b60f12-a20c-4977-99ea-f9affdb8e5f2",
"accountId": "3fa8372d-b51d-44ab-a456-43e947e4be10",
"symbol": "BTC-USD",
"orderQty": "1000",
"side": "SELL",
"currency": "USD",
"orderType": "LIMIT",
"limitPrice": "21000",
"timeInForce": "GTC",
"orderStatus": "REJECTED",
"execId": "6a33f72c-ec2e-4c7a-b443-29de3f884145",
"execType": "REJECT",
"avgPx": "0",
"avgPxAllIn": "0",
"cumQty": "0",
"fillPx": "0",
"fillQty": "0",
"leavesQty": "0",
"cancelQty": "0",
"rejectReason": "Invalid request",
"rejectReasonText": "invalid price: 21500.0001, must be multiplication of 0.01",
"fee": "0",
"feeCurrency": "",
"submitTime": "2023-03-12T22:22:09.909251Z",
"transactTime": "2023-03-12T22:22:09.925050Z"
}
}
```
### Request parameters
| Parameter | Type | Required | Description |
| ------------- | ----------------------------- | --------- | ----------------------------------------------------------------------------- |
| `messageType` | string | | `NewOrderSingle` |
| `timestamp` | string (date-time) | | RFC3990 date-time string |
| `clOrderId` | string | | Client order ID, must be unique; recommend UUID |
| `accountId` | string | | Anchorage brokerage account ID |
| `symbol` | string | | Trading symbol, e.g. `"BTC-USD"` |
| `side` | `"BUY"` \| `"SELL"` | | Side for the order |
| `orderQty` | string | | Order quantity |
| `currency` | string | | Currency the order quantity is specified in; can be either side of the symbol |
| `orderType` | `"MARKET"` \| `"LIMIT"` | | Order type |
| `limitPrice` | string | | Limit price; required if `orderType` is `LIMIT` |
| `timeInForce` | `"FOK"` \| `"GTC"` \| `"IOC"` | | FOK = Fill Or Kill, GTC = Good Till Cancel, IOC = Immediate Or Cancel |
### Response parameters
| Parameter | Type | Required | Description |
| ------------------ | ----------------------------- | --------- | ---------------------------------------------------------------------------------------- |
| `messageType` | string | | `ExecutionReport` |
| `timestamp` | string (date-time) | | RFC3990 date-time string |
| `clOrderId` | string | | Client order ID as specified on the order request |
| `orderId` | string | | Anchorage order ID |
| `accountId` | string | | Anchorage brokerage account ID |
| `symbol` | string | | Trading symbol as specified on the order request |
| `side` | `"BUY"` \| `"SELL"` | | Order side as specified on the order request |
| `orderQty` | string | | Order quantity as specified on the order request |
| `currency` | string | | Currency as specified on the order request |
| `orderType` | `"MARKET"` \| `"LIMIT"` | | Order type as specified on the order request |
| `limitPrice` | string | | Limit price as specified on the order request |
| `timeInForce` | `"FOK"` \| `"GTC"` \| `"IOC"` | | Time in force as specified on the order request |
| `orderStatus` | string | | `PENDING`, `NEW`, `REJECTED`, `PENDING_CANCEL`, `CANCELED`, `FILLED`, `PARTIALLY_FILLED` |
| `execId` | string | | Execution ID, can be used to query for trades |
| `execType` | string | | `NEW`, `FILL`, `CANCEL`, `REJECT`, `CANCEL_REJECT` |
| `avgPx` | string | | Average price of filled portion of the order |
| `avgPxAllIn` | string | | Average price including fees of filled portion |
| `cumQty` | string | | Cumulative quantity filled |
| `fillPx` | string | | Fill price of this execution (excluding fees) |
| `fillQty` | string | | Fill quantity of this execution (`execType="FILL"`) |
| `leavesQty` | string | | Leaves quantity of this order |
| `cancelQty` | string | | Canceled quantity of this order |
| `fee` | string | | Anchorage commission charged for this execution |
| `feeCurrency` | string | | Currency that the commission is charged in |
| `rejectReason` | string | | Reason for rejection |
| `rejectReasonText` | string | | Additional description for reason of reject |
| `submitTime` | string (date-time) | | Order submission time in RFC3990 format |
| `transactTime` | string (date-time) | | Transaction time in RFC3990 format |
***
## CancelOrderRequest
Cancel an order. `origClOrderId` and `accountId` must match the original order request. `orderId` must match the order ID returned on execution reports.
Cancel requests on any completed order will be rejected.
**Example cancel request:**
```json theme={null}
{
"messageType": "OrderCancelRequest",
"timestamp": "2023-03-12T22:22:09.925952Z",
"payload": {
"origClOrderId": "3fa8372d-b51d-44ab-a456-43e947e4be10",
"orderId": "0d479b19-1012-42d1-9558-ffb4d8db7153",
"accountId": "3fa8372d-b51d-44ab-a456-43e947e4be10"
}
}
```
**Example response:**
```json theme={null}
{
"messageType": "ExecutionReport",
"timestamp": "2023-03-13T13:44:05.244315Z",
"version": "1.0",
"seqNum": 9,
"payload": {
"clOrderId": "3fa8372d-b51d-44ab-a456-43e947e4be10",
"orderId": "0d479b19-1012-42d1-9558-ffb4d8db7153",
"accountId": "3fa8372d-b51d-44ab-a456-43e947e4be10",
"symbol": "BTC-USD",
"side": "SELL",
"orderQty": "10000",
"currency": "USD",
"orderType": "LIMIT",
"limitPrice": "23500",
"timeInForce": "GTC",
"orderStatus": "CANCELED",
"cumQty": "0",
"cancelQty": "10000",
"leavesQty": "0",
"execId": "7cfcbb67-76fa-46c3-8535-655fd8fe0eb8",
"execType": "CANCEL",
"submitTime": "2023-03-13T13:44:05.182005Z",
"transactTime": "2023-03-13T13:44:05.185177Z"
}
}
```
**Example cancel reject response:**
```json theme={null}
{
"messageType": "ExecutionReport",
"timestamp": "2023-03-13T13:59:01.668938Z",
"payload": {
"clOrderId": "3fa8372d-b51d-44ab-a456-43e947e4be10",
"orderId": "0d479b19-1012-42d1-9558-ffb4d8db7153",
"accountId": "3fa8372d-b51d-44ab-a456-43e947e4be10",
"symbol": "BTC-USD",
"side": "SELL",
"orderQty": "10000",
"currency": "USD",
"orderType": "LIMIT",
"limitPrice": "23500",
"timeInForce": "GTC",
"orderStatus": "NEW",
"execId": "16532303-8478-4a6e-82db-5920e6553525",
"execType": "CANCEL_REJECT",
"avgPx": "0",
"avgPxAllIn": "0",
"cancelQty": "0",
"cumQty": "0",
"leavesQty": "10000",
"rejectReason": "Invalid account",
"rejectReasonText": "Invalid account id for cancel request",
"submitTime": "2023-03-13T13:59:00.151982Z",
"transactTime": "2023-03-13T13:59:01.668610Z"
}
}
```
### Request parameters
| Parameter | Type | Required | Description |
| --------------- | ------------------ | --------- | ---------------------------------------------------------------- |
| `messageType` | string | | `OrderCancelRequest` |
| `timestamp` | string (date-time) | | RFC3990 date-time string |
| `origClOrderId` | string | | Client order ID as specified on the order request |
| `orderId` | string | | Anchorage order ID |
| `accountId` | string | | Anchorage brokerage account ID as specified on the order request |
**Response:** See response parameters for [NewOrderSingle](#newordersingle).
***
## ExecutionReportResendRequest
Resend execution reports for an order. Allows a client to request execution reports for a live or completed order. If the order is completed, all previous execution reports are sent again. If the order is still alive, in addition to any previous execution reports, newer reports will be streamed on this WebSocket as they occur.
Use this to synchronize order states after a WebSocket disconnect.
**Example resend request:**
```json theme={null}
{
"messageType": "ExecutionReportResendRequest",
"timestamp": "2023-03-12T22:22:09.925952Z",
"payload": {
"origClOrderId": "3fa8372d-b51d-44ab-a456-43e947e4be10",
"orderId": "0d479b19-1012-42d1-9558-ffb4d8db7153",
"accountId": "3fa8372d-b51d-44ab-a456-43e947e4be10"
}
}
```
### Request parameters
| Parameter | Type | Required | Description |
| --------------- | ------------------ | --------- | ---------------------------------------------------------------- |
| `messageType` | string | | `ExecutionReportResendRequest` |
| `timestamp` | string (date-time) | | RFC3990 date-time string |
| `origClOrderId` | string | | Client order ID as specified on the order request |
| `orderId` | string | | Anchorage order ID |
| `accountId` | string | | Anchorage brokerage account ID as specified on the order request |
**Response:** A stream of execution reports. See response parameters for [NewOrderSingle](#newordersingle).
# Mapping wallets to on-chain addresses
Source: https://docs.anchorage.com/knowledge-base/platform/developers/wallet-address-model
Map wallet IDs to on-chain addresses across account-based, UTXO, and compatible networks.
An Anchorage Digital wallet isn't necessarily an on-chain address. Sometimes the two line up one to one, sometimes one wallet pools many addresses, and sometimes several wallets sit behind a single address. This page shows each case, then lets you try the permutations.
Two ideas are worth keeping apart as you read. An **on-chain wallet** is a keypair and the address derived from it, and it works on every network that shares its key derivation. An **Anchorage Digital wallet** is a container for balances on one network inside one vault, with its own `walletId`. For where wallets sit in the wider structure, see [Account hierarchy](/knowledge-base/platform/developers/account-hierarchy).
## How a wallet ID maps to addresses
The `walletId` is the identifier your integration operates on. Withdrawals, balances, and calls to `GET /v2/wallets` all name a wallet, never an address. How many on-chain addresses sit underneath it depends on the network's transaction model, which [Account hierarchy](/knowledge-base/platform/developers/account-hierarchy) covers in detail.
On account-based networks the wallet and the address are interchangeable in practice, which is why the distinction is easy to miss. On UTXO networks they clearly aren't: a transfer pulls from multiple source addresses automatically, and the unspent remainder returns to a new change address inside the same wallet.
## What one address can hold
A single on-chain address holds more than one type of asset. The network's native asset and every token issued on that network arrive at the same address and sit in the same wallet, each with its own balance.
Because the address is shared across the whole token layer, you can't add a second deposit address to an existing wallet on an account-based network. Create another wallet in the vault instead, and it comes with its own `walletId`.
## Two ways to map compatible networks
Compatible networks share a key derivation, so one keypair works across all of them. In the API, each network carries a `keyFamily`: an opaque identifier where two networks can share wallet private keys when their values match. Treat it as an equality comparison within a single response, and don't parse or cache the value.
Address sharing is available on EVM, SPL, and Tendermint networks. When you create wallets on more than one network in a family, you choose between two setups.
The choice is made at creation: the selected network only, all compatible networks, or a subset you pick. See [Creating and managing wallets](/knowledge-base/platform/users/wallet-creation) for the flow, including how to extend an existing wallet's address onto more networks later.
Balances never cross networks on their own in either setup. Moving assets from one compatible network to another means bridging, not transferring.
## Plan a configuration
Set a network, decide how many networks to cover, and pick an address strategy. The diagram redraws to show the wallets you'd create, their wallet IDs, and the addresses underneath them.
## What follows from the model
* The first wallet created for a network in a vault becomes that vault's default wallet, and the source of funds for external withdrawals, trade settlement, and holds executed by API.
* A generated address stays live on the blockchain and can't be deleted, so it keeps receiving. Addresses can be reused.
* Trusted destinations are per network. The same address on two networks needs two entries, and a withdrawal fails if the address is allowlisted on a different network than the one you send on. See [Trusted destinations](/knowledge-base/platform/developers/move-money/setup/trusted-destinations).
* On certain networks, creating one wallet also generates the wallets for all compatible networks and archives them. Archived wallets still receive deposits, but unarchive them before staking or withdrawing.
* A deposit that arrives on a compatible network where you have no wallet is still detected on the shared address. We run spam attribution and create the wallet if the deposit clears.
* Each asset carries an `availableBalance` and a `totalBalance` per wallet. See [Account hierarchy](/knowledge-base/platform/developers/account-hierarchy) for what each one includes.
# Configure sandbox
Source: https://docs.anchorage.com/knowledge-base/platform/developers/wealth/wealth-management-api-config
Set up API permission groups, API keys, and the shared Anchorage Digital key for the wealth management integration.
Before setting up API keys for sandbox or production, configure a permission group, generate your master API key, and provision the shared key Anchorage Digital uses to settle trades on your behalf.
## API permission group
Configure permissions before generating an API key.
Generate an API access key in the [Anchorage Digital web dashboard](https://anchoragelogin.com/) under the API 2.0 section. Save the key securely as keys are not recoverable.
Scroll to **API permission groups** and select **Create a new group**.
| Permission | Enable? | Notes |
| :----------------------------- | :------ | :-------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Initiate withdrawal | No | Not required — withdrawals occur from vaults/wallets, not ledgered accounts. |
| Read subaccounts | **Yes** | Read all balances and transactions on the wealth management ledger. |
| Write subaccounts | **Yes** | Create transactions on the wealth management ledger. |
| Execute trades | **Yes** | Trade from ledger balances. If not visible, the user is not an enabled trader. |
| Read trades | **Yes** | Read all trades and trade settlements. Select **All trades on the org**. If not visible, contact your account representative to enable trade permissions. |
| Onboarding | **Yes** | Enables API-based client onboarding. |
| Read deposit attribution | **Yes** | Access past and current deposit attributions. |
| Configure webhooks | **Yes** | Set up webhook notifications. |
| Read vault | **Yes** | Read balances across all wallets. Select **All vaults**. |
| Create new address | **Yes** | Create deposit wallets for account funding. |
| Transfer | No | Not needed for wealth management integration. |
| Propose and accept settlements | No | Not needed for wealth management integration. |
| Authorize settlements | No | Not needed for wealth management integration. |
After submitting the permission group, endorse the operation on the iOS app to achieve quorum. Anchorage Digital will then perform a risk review before the permission group can be used to create an API key.
## Master API key generation
This in-app widget is intended for staging and testing only. For production key pairs, use the Python script below or your own key generation tooling instead.
We can't yet guarantee we have every control in place to safely generate and handle keys on your behalf. Generating your own keys keeps that risk with you, rather than shifting it to Anchorage Digital.
```python theme={null}
# https://pypi.org/project/PyNaCl/
import nacl
import nacl.signing
import secrets
seed = secrets.token_bytes(32)
signing_key = nacl.signing.SigningKey(seed)
print('Signing key:')
print(signing_key.encode().hex())
print('Public key:')
print(signing_key.verify_key.encode().hex())
```
Select the permission group created above, and use the public key from step 1 to create your API key.
Copy the API key immediately as it will not be displayed again. If lost, revoke the key and generate a new one.
For read-only keys issued to third-party vendors (e.g., data aggregation, reconciliation), provision with read-only permissions only. Read-only keys do not require an Ed25519 key pair — use the "I don't want to provision a signing key" toggle when creating the key.
## Create the shared API key for Anchorage Digital
The shared API key allows Anchorage Digital to settle trades on behalf of the wealth manager. It is provisioned by the wealth manager but owned and managed by Anchorage Digital.
Go to the **API 2.0** section of the [Anchorage Digital web dashboard](https://anchoragelogin.com/).
Select **Shared API keys** in the top navigation.
Review and accept the terms and conditions to proceed.
The permission group is pre-configured. Select the applicable options, then quorum approve the operation. Wait for Anchorage Digital to complete its risk review before proceeding.
This step also requires quorum approval and an Anchorage Digital risk review. No Ed25519 key pair is required — Anchorage Digital manages this key.
In the API 2.0 keys table, verify the key status is green and marked **Unused** after Anchorage Digital approval.
## API testing
Read-only APIs can be tested directly in the reference docs using your sandbox API key. Production keys will not work in the sandbox environment.
For write APIs, generate a request signature outside of Postman or the reference docs.
**API signing:** see the [Request signing](/knowledge-base/platform/developers/request-signing) guide.
**Host URLs:**
| Environment | URL |
| :---------- | :------------------------------------- |
| Sandbox | `https://api.anchorage-staging.com/v2` |
| Production | `https://api.anchorage.com/v2` |
## Sandbox setup
Some steps only apply to production (e.g., onboarding, trading, settlement). Note the following before beginning sandbox testing:
* Verify you are onboarded to the sandbox iOS app and have web dashboard access. Onboarding details are sent by Anchorage Digital via email.
* Admin users must download the iOS app for quorum approvals and API key creation.
### Sandbox testnet assets
All sandbox activity uses testnet assets only.
| Mainnet asset | Recommended testnet asset |
| :------------ | :------------------------ |
| Bitcoin | `BTC_S` (Signet) |
| Ethereum | `ETHHOODI` (Hoodi) |
| USDC | `USDANCHOL` (Hoodi) |
| Solana | `SOL_TD` (Devnet) |
# Asset-backed loans
Source: https://docs.anchorage.com/knowledge-base/platform/developers/wealth/wealth-management-asset-backed-loans
Offer your clients loans backed by their digital assets, monitored through Anchorage Digital's collateral management system.
Let your clients borrow against their digital assets without selling them, while Anchorage Digital prices the collateral and monitors loan-to-value in real time. You register the loan and respond to margin events; Anchorage Digital handles continuous risk monitoring so you don't have to build it yourself.
## How it works
When you approve a loan, create a collateral package specifying the pledgor (your end client), the pledged assets, and the loan-to-value thresholds that should trigger a warning, a margin call, or a critical alert.
Register the loan itself as an exposure against that collateral package, tagged with your own loan ID.
As the loan progresses, record activity: the initial pledge, any top-ups or margin returns, and the eventual payoff.
Anchorage Digital continuously prices the pledged assets and calculates loan-to-value in real time, alerting you as thresholds are approached or crossed.
When a threshold is breached, respond directly — for example, requesting a margin return — or, if pre-configured, let Anchorage Digital take an agreed action automatically as collateral manager.
Loan collateral can be held in the same subaccount as your client's tradable funds, so you don't need a separate account structure to offer asset-backed loans alongside custody and trading.
For the full collateral management concepts — terminology, package states, configured actions, pricing methodology, and liquidation mechanics — see [Atlas collateral management](/knowledge-base/platform/developers/atlas/atlas-collateral-management). This page covers the wealth-management-specific integration flow only.
Whether you or Anchorage Digital handles collateral unlock and liquidation depends on whether Anchorage Digital is configured as collateral manager for your program. Confirm this during setup.
***
## Integration steps
These calls require the **Manage Collateral Packages** and **Read vault activity** [API permissions](/knowledge-base/platform/developers/permission-groups). `POST` requests also require [request signing](/knowledge-base/platform/developers/request-signing).
### Step 1: Set up the collateral record
**`POST /v2/collateral_management/packages`**
Specify the pledgor, the pledged assets, and the loan-to-value thresholds that trigger a warning, margin call, or critical alert.
```bash Request theme={null}
curl --request POST \
--url https://api.anchorage-staging.com/v2/collateral_management/packages \
--header 'Api-Access-Key: [API Key]' \
--header 'Api-Signature: [Signature]' \
--header 'Api-Timestamp: [Timestamp]' \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--data '{
"pledgorId": "end-client-042",
"securedPartyId": "your-lending-desk",
"collateralAssetsConfig": [
{
"asset": { "type": "ANCHORAGECUSTODY", "assetType": "BTC" },
"weight": "1",
"liquidationPriority": 1,
"priceSource": "COINBASEPRO"
}
],
"priceStrategy": "MID",
"marginCall": {
"ltv": "0.70",
"warningLtv": "0.65",
"returnToLtv": "0.60",
"curePeriod": "24h",
"curePeriodProtection": true,
"topUpType": "LTV",
"action": "NONE"
},
"critical": {
"ltv": "0.85",
"warningLtv": "0.80",
"returnToLtv": "0.70",
"defaultNotice": true,
"action": "FULL"
}
}'
```
```json Response theme={null}
{
"packageId": "9c3e5a1f-2b4d-4e6a-8f7c-1d5b9a2e4c6f"
}
```
### Step 2: Register the loan
**`POST /v2/collateral_management/exposures`**
```bash Request theme={null}
curl --request POST \
--url https://api.anchorage-staging.com/v2/collateral_management/exposures \
--header 'Api-Access-Key: [API Key]' \
--header 'Api-Signature: [Signature]' \
--header 'Api-Timestamp: [Timestamp]' \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--data '{
"collateralPackageID": "9c3e5a1f-2b4d-4e6a-8f7c-1d5b9a2e4c6f",
"clientReferenceId": "your-loan-id-001",
"type": "LOAN",
"priceStrategy": "MID",
"assetTrackingConfig": {
"asset": { "type": "ANCHORAGECUSTODY", "assetType": "BTC" },
"liquidationPriority": 1
}
}'
```
```json Response theme={null}
{
"exposureId": "4f8b6d2a-9e1c-4a3f-b7d5-2c8e6a4f1b9d"
}
```
### Step 3: Record the initial pledge
Record the collateral deposit against the package, and the loan principal against the exposure.
```bash Request — collateral deposit theme={null}
curl --request POST \
--url https://api.anchorage-staging.com/v2/collateral_management/operations \
--header 'Api-Access-Key: [API Key]' \
--header 'Api-Signature: [Signature]' \
--header 'Api-Timestamp: [Timestamp]' \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--data '{
"type": "COLLATERAL_PACKAGE",
"typeId": "9c3e5a1f-2b4d-4e6a-8f7c-1d5b9a2e4c6f",
"action": "INITIAL_DEPOSIT",
"asset": { "type": "ANCHORAGECUSTODY", "assetType": "BTC" },
"quantity": "1.5",
"idempotentId": "your-loan-id-001-deposit-1"
}'
```
```bash Request — loan funding theme={null}
curl --request POST \
--url https://api.anchorage-staging.com/v2/collateral_management/operations \
--header 'Api-Access-Key: [API Key]' \
--header 'Api-Signature: [Signature]' \
--header 'Api-Timestamp: [Timestamp]' \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--data '{
"type": "EXPOSURE",
"typeId": "4f8b6d2a-9e1c-4a3f-b7d5-2c8e6a4f1b9d",
"action": "INITIAL_FUNDING",
"asset": { "type": "ANCHORAGECUSTODY", "assetType": "USD" },
"quantity": "50000",
"idempotentId": "your-loan-id-001-funding-1"
}'
```
### Step 4: Monitor loan-to-value
**`GET /v2/collateral_management/packages/{packageId}`**
Returns `currentLtv`, `state` (`HEALTHY`, `MARGIN_CALL`, `CRITICAL`, and other values), `packageValue`, and `exposureValue`. Alerts fire automatically by email and webhook as the thresholds set in Step 1 are crossed — see [Email and webhook notifications](/knowledge-base/platform/developers/atlas/atlas-collateral-management#email-and-webhook-notifications).
### Step 5: Respond to a threshold breach
Request a margin return once the package enters the `MARGIN_RETURN` state:
```bash Request theme={null}
curl --request POST \
--url https://api.anchorage-staging.com/v2/collateral_management/packages/9c3e5a1f-2b4d-4e6a-8f7c-1d5b9a2e4c6f/requests/margin-return \
--header 'Api-Access-Key: [API Key]' \
--header 'Api-Signature: [Signature]' \
--header 'Api-Timestamp: [Timestamp]' \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--data '{
"assetAmounts": [
{ "assetTypeID": "BTC", "value": "0.2" }
],
"idempotencyKey": "your-loan-id-001-margin-return-1",
"useGasStation": false
}'
```
Or, once your client tops up collateral in response to a margin call:
```bash Request theme={null}
curl --request POST \
--url https://api.anchorage-staging.com/v2/collateral_management/operations \
--header 'Api-Access-Key: [API Key]' \
--header 'Api-Signature: [Signature]' \
--header 'Api-Timestamp: [Timestamp]' \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--data '{
"type": "COLLATERAL_PACKAGE",
"typeId": "9c3e5a1f-2b4d-4e6a-8f7c-1d5b9a2e4c6f",
"action": "TOP_UP",
"asset": { "type": "ANCHORAGECUSTODY", "assetType": "BTC" },
"quantity": "0.3",
"idempotentId": "your-loan-id-001-topup-1"
}'
```
# Crypto deposits and withdrawals
Source: https://docs.anchorage.com/knowledge-base/platform/developers/wealth/wealth-management-crypto-deposits-withdrawals
Fund end-client accounts with in-kind digital asset deposits, attribute them, and process withdrawals to trusted destinations.
## How it works
Create a subaccount-specific deposit wallet for the asset your client wants to deposit.
Share the deposit address, along with the blockchain and asset details.
Detect the deposit via webhook or polling, then attribute it to the correct end client.
When your client wants to withdraw, register their external address as a trusted destination, then initiate the withdrawal.
***
## Fund accounts with digital assets
Steps must be completed in order — out-of-sequence execution risks funds being lost or returned.
### Deposit attribution
**Status values**
| `status` | Details |
| :----------------- | :----------------------------------------------------------------------------------------------------------------------- |
| `PENDING` | Deposit landed after Anchorage Digital auto-attribution attempt. Spam deposits marked by Anchorage will not appear here. |
| `INITIATED` | Deposit detected; auto-attribution in progress. Moves to `PENDING` if auto-attribution fails. |
| `ATTRIBUTED` | Terminal state — happy path. |
| `UNDER_REVIEW` | Attributed but triggered a sanctions hit pending compliance clearance. |
| `BLOCKED` | Confirmed true sanctions hit. |
| `NON_ATTRIBUTABLE` | Semi-terminal state for specific edge cases. |
**Attribution type values**
| `attributionType` | Details |
| :---------------- | :------------------------------------------------------------- |
| `MANUAL_STAFF` | Attributed by Anchorage Digital staff. |
| `MANUAL_CLIENT` | Attributed by wealth manager via web dashboard. |
| `CLIENT_API` | Attributed by wealth manager via API key. |
| `AUTOMATIC` | Attributed via travel rule message from originating VASP. |
| `SPAM` | Attributed as spam by Anchorage Digital or the wealth manager. |
| `TRUSTED_SOURCES` | Attributed automatically using a designated trusted source. |
**Trusted sources**
Trusted sources auto-attribute recurring deposits from the same address. Create them in the Anchorage Digital web dashboard (API not available in production).
Trusted sources should not be used if a single source address is shared by multiple end clients. Doing so may cause incorrect attribution and require the wealth manager to provide additional originator details to Anchorage Digital.
**Spam / unknown deposits**
Attribute dust or spam deposits as `SPAM` using **`POST /v2/deposit-attributions/{depositTransactionId}/spam`**. This prevents unwanted balances from appearing on the end client's account. Anchorage Digital will sweep these funds from on-chain wallets using the shared API key as needed.
**Automated attribution from VASPs**
Crypto deposits from VASPs over \$2,100 (the travel rule threshold) are automatically attributed if Anchorage Digital receives a travel rule message from an active TRUST network VASP. This is not instant — use the attribution API for faster fund access.
### Step 1: Get your `vaultId`
**`GET /v2/vaults`**
```bash Request theme={null}
curl --request GET \
--url https://api.anchorage-staging.com/v2/vaults \
--header 'Api-Access-Key: [API Key]' \
--header 'accept: application/json'
```
```json Response theme={null}
{
"data": [
{
"accountName": "Wealth Manager - FBO Program Customers",
"description": "",
"name": "John Doe_Deposit wallet_Subaccount_123456789987654323456",
"type": "VAULT",
"vaultId": "7d04d1b820f1b5a903e47fd3019c58f3"
}
]
}
```
### Step 2: Create a deposit wallet for the subaccount
**`POST /v2/vaults/{vaultId}/wallets`**
Create one wallet per subaccount per asset, specifying `subaccountId`. Create wallets on demand — when the customer requests a deposit address — rather than pre-creating wallets for every supported asset.
**Recommended naming convention:** `[PC name]_[Subaccount #]_Deposit Wallet`
Wallet creation is limited to 10 wallets per asset per 30 minutes. This limit will increase in coming months.
```bash Request theme={null}
curl --request POST \
--url https://api.anchorage-staging.com/v2/vaults/7d04d1b820f1b5a903e47fd3019c58f3/wallets \
--header 'Api-Access-Key: [API Key]' \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--data '{
"networkId": "BTC",
"walletName": "John Doe_ec761b5e-fd2c-497a-a9a0-f8738ac97bdf_Bitcoin Deposit Wallet_1",
"subaccountId": "ec761b5e-fd2c-497a-a9a0-f8738ac97bdf"
}'
```
```json Response theme={null}
{
"data": {
"depositAddress": {
"address": "3KEFt8iLAGSHhKvQsVUabmAHZdWar45PnW",
"addressId": "2be7ad5e4dccbdf2d82b77113d908e5cb",
"addressSignaturePayload": "7b225465787441646472657373223a22334b45467438694c41475348684b765173565561626d41485a645761723435506f57227d",
"signature": "dcb09503a0dfd592749f6298a59ea46aac549aa56a1127fa51efb1ad34663eabb55bab24c9c87ff7c0e09e6d9154daeadc1805e5cf297abd8a8b404bb6b7910b"
},
"isArchived": false,
"isDefault": false,
"networkId": "BTC",
"subaccountId": "ec761b5e-fd2c-497a-a9a0-f8738ac97bdf",
"vaultId": "7d04d1b820f1b5a903e47fd3019c58f3",
"vaultName": "Advisor 1, FBO Program Customers",
"walletId": "6aabaa5127f3757de379e724f69d6fa10",
"walletName": "John Doe_ec761b5e-fd2c-497a-a9a0-f8738ac97bdf_Bitcoin Deposit Wallet_1"
}
}
```
**Sandbox testnet assets:** `BTC_T` (BTC testnet), `ETHHOL` (ETH Holesky), `USDANCHOL` (USDC Holesky)
Share the deposit address with the end client, along with the blockchain details (e.g., Ethereum mainnet vs. Base) and any deposit attribution requirements.
For the first few deposits, have the end client send a small test amount to confirm the address and network are correct before transferring the full balance. Ensure both parties are aligned on the exact asset symbol and supported network — deposits to the wrong network may result in lost funds.
### Step 3: Identify a new deposit
Deposit confirmations are not immediate — they typically require 2 on-chain confirmations, which may take a few minutes.
**Option A:** Poll for pending attributions — **`GET /v2/deposit-attributions?status=PENDING`**
```json Response theme={null}
{
"data": [
{
"assetType": "BTC",
"depositTransactionId": "22a73be305a4131e2b3439ca5d0fbb7a",
"status": "PENDING",
"subaccountId": "cb80459c-a930-444e-8f17-69ba9d0e122f"
}
]
}
```
**Option B:** Webhook notification — subscribe to `deposit.pending-attribution`:
```json Webhook payload theme={null}
{
"payload": "eyJ0cmFuc2FjdGlvbklkIjoiNjE4Y2JkNTVlNzE2ZmFlMGVkODNjYTcyOWM4MDI2NmEifQ==",
"timestamp": 1729112450,
"message_id": "aa2dbc06-1665-44c0-bb8e-d2b0ad15a564",
"event_type": "deposit.pending-attribution"
}
```
The `message_id` maps to the `depositTransactionId`.
Ensure end clients only deposit supported assets. Deposits of unsupported assets into a wallet will result in lost funds.
### Step 4: Attribute the deposit
**`PATCH /v2/deposit-attributions/{depositTransactionId}`**
In production, collect AML deposit attribution data from the end client before sharing the deposit address — this enables automatic attribution once the deposit is detected.
`sourceWalletType` values:
| Value | Description |
| :------------ | :------------------------------------------------------------------------------------------- |
| `CUSTODIAL` | Third party holds the private key (e.g., Binance, Coinbase, Kraken, BitGo). |
| `SELF_HOSTED` | Owner holds the private key (e.g., MetaMask, Trust Wallet, Ledger, Trezor, Exodus, Phantom). |
For spam/dust deposits, use **`POST /v2/deposit-attributions/{depositTransactionId}/spam`** instead to prevent unwanted balances from appearing on the account.
```bash Request theme={null}
curl --request PATCH \
--url https://api.anchorage-staging.com/v2/deposit-attributions/aa2dbc06-1665-44c0-bb8e-d2b0ad15a564 \
--header 'Api-Access-Key: [API Key]' \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--data '{
"originatorName": "John Doe",
"originatorCountry": "US",
"sourceWalletType": "SELF_HOSTED",
"notes": "US"
}'
```
```json Response (attributed) theme={null}
{
"data": [
{
"assetType": "BTC",
"attributedAt": "2024-04-09T19:31:02.046634Z",
"attributionType": "CLIENT_API",
"depositTransactionId": "aa2dbc06-1665-44c0-bb8e-d2b0ad15a564",
"notes": "Example Attribution",
"originatorCountry": "US",
"originatorName": "John Doe",
"sourceWalletType": "SELF_HOSTED",
"status": "ATTRIBUTED",
"subaccountId": "cb80459c-a930-444e-8f17-69ba9d0e122f"
}
]
}
```
After attributing in-kind deposits, [update the missing cost basis](/knowledge-base/platform/developers/wealth/wealth-management-tax#step-2-update-missing-cost-basis) via **`PATCH /v2/tax/transaction/{transactionId}`**.
### Step 5: View account balances
**`GET /v2/subaccounts/customers/{customerId}/accounts`**
```bash Request theme={null}
curl --request GET \
--url https://api.anchorage-staging.com/v2/subaccounts/customers/{customerId}/accounts \
--header 'Api-Access-Key: [API Key]' \
--header 'accept: application/json'
```
```json Response theme={null}
{
"data": [
{
"subaccountId": "cb80459c-a930-444e-8f17-69ba9d0e122f",
"name": "A1234_John Doe_Strat1",
"customerId": "cf326d89b501d7ff2d1c7b7ffea4bd305a6561b54c9c6158160e17b5aca5cec2",
"fees": [
{ "type": "MANAGEMENT", "rate": 0.01, "startDate": "2025-02-18", "isBillable": true },
{ "type": "CUSTODY", "rate": 0.01, "startDate": "2025-02-18", "isBillable": true }
],
"balances": [
{ "assetType": "BTC", "totalBalance": "100", "availableForWithdrawal": "100", "availableForTrading": "100" },
{ "assetType": "USD", "totalBalance": "100000", "availableForWithdrawal": "100000", "availableForTrading": "100000" }
]
}
]
}
```
***
## Withdraw digital assets
**New programmatic in-kind withdrawals (released 2025-04-15).** Three key changes:
1. New create trusted destinations API.
2. New DocuSign approval required from the end client before creating the trusted destination.
3. Updated withdrawal API payload for withdrawals to trusted destinations.
4. API permission and key updates required.
### Step 1: Update API key permissions
Add the following two permissions to your API key permission group:
* **Withdrawal** — Yes
* **Manage trusted destinations** — Yes
Quorum approve the change before proceeding.
### Step 2: Add trusted destinations
Submit trusted destination requests via **`POST /v2/trusted_destinations`** for each end-client's external withdrawal address.
For wealth management integrations, trusted destinations are tied to an `owner` representing the end client (`customerId`).
**After submission:** A DocuSign is sent to the end client for each destination. Once signed, the Anchorage Digital ops team reviews and approves. If issues arise, Anchorage Digital will reach out.
```bash theme={null}
curl --request POST \
--url https://api.anchorage-staging.com/v2/trusted_destinations \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--data '{
"idempotentId": "YOUR_GENERATED_UUID_HERE",
"trustedDestinations": [
{
"assetType": "ETH",
"address": "0x430EF7FAB8e10dFb8B7c50c2026d0e247FEE4B8",
"name": "Test Ethereum Address 3",
"trustedDestinationAmlQuestionnaire": {
"destinationType": "SELFHOSTED_WALLET",
"selfhostedDescription": "Personal ETH wallet for testing",
"selfhostedWalletOwner": "PERSON_OR_ENTITY",
"recipientType": "PERSON",
"recipientFirstName": "John",
"recipientLastName": "Doe",
"recipientFullName": "John Doe",
"recipientCountry": "US",
"recipientStreetAddress": "123 Main St",
"recipientCity": "San Francisco",
"recipientStateProvince": "CA",
"recipientPostalCode": "94105"
},
"description": "Test Ethereum wallet for demo purposes",
"memo": "ETH demo wallet 3",
"isNetworkLevel": false
}
],
"owner": {
"type": "CUSTOMER",
"id": "7266559476aac38fc8c7c2022f93a9d1b9b618b1c9e2b4387840b595dcd374aa"
}
}'
```
### Step 3: Initiate the withdrawal
Use **`POST /v2/transactions/withdrawal`**. Anchorage Digital account admins will need to verify on their iOS devices. Once quorum is complete, the operation proceeds through risk review, then broadcasts on-chain.
Admins can batch approve multiple operations on iOS. See [Batched endorsements](/knowledge-base/platform/users/sending-assets#batched-endorsements).
Multiple withdrawals for the same asset queued simultaneously may be processed sequentially rather than in parallel. Flagged withdrawals may also delay same-asset withdrawals.
```json Withdrawal request theme={null}
{
"source": {
"id": "15bb8b12-d991-45d2-b784-c83c4449265b",
"type": "SUBACCOUNT"
},
"assetType": "ETH",
"destination": {
"id": "0xf0Ed16EeedD8111B40De252467eE9d0E14cbfe99",
"type": "ADDRESS"
},
"amount": "1",
"description": "",
"withdrawalAmlQuestionnaire": {
"useTrustedDestinationAml": true,
"purpose": "INTRA_COMPANY"
}
}
```
**`purpose` values:** `TRADING_SETTLEMENT`, `LENDING`, `INVESTMENT`, `EXPENSES`, `FEE_PAYMENT`, `GRANT_PAYMENT`, `PRIZE_AWARD`, `GIFT`, `REIMBURSEMENT`, `REBALANCE`, `INTRA_COMPANY`
# Fiat deposits and withdrawals
Source: https://docs.anchorage.com/knowledge-base/platform/developers/wealth/wealth-management-fiat-deposits-withdrawals
Fund end-client accounts with USD deposits and process withdrawals.
## How it works
Generate a unique USD wire memo per account so incoming wires are attributed automatically.
The client wires USD from an account held in their own name, including the memo.
Once settled, funds are available to trade or withdraw.
You initiate the withdrawal via API. Anchorage Digital sends a DocuSign to the client for approval, then wires the funds back to the originating account.
***
## Fund accounts with USD
Generate a USD wire memo per account via API and share it with the end client. Include the memo in the wire to Anchorage Digital to ensure proper attribution.
### USD funding considerations
* **Wires without memos are returned** — Any wire without a memo field is subject to return. Anchorage Digital will use best efforts to determine the recipient but requires written confirmation from the wealth manager before attributing.
* **Multiple accounts** — If the end client has multiple accounts, they can fund one and rebalance USD across accounts using the account transactions API.
* **Third-party wires not supported** — The originating bank account must be held in the end client's name. Payments from accounts not in the end client's name will be returned.
### Step 1: Generate a wire memo
**`GET /v2/subaccounts/accounts/{subaccountId}/bank-info`**
```bash Request theme={null}
curl --request GET \
--url https://api.anchorage-staging.com/v2/subaccounts/accounts/cb80459c-a930-444e-8f17-69ba9d0e122f/bank-info \
--header 'Api-Access-Key: [API Key]' \
--header 'accept: application/json'
```
```json Response theme={null}
{
"data": {
"bank": "Customers Bank",
"bankAccountNr": "1234567",
"bankAddress": "123 Test",
"bankRoutingNr": "123456789",
"bankSwiftCode": "CUESUS33",
"beneficiaryAddress": "123 Test",
"beneficiaryName": "Anchorage Digital Bank NA",
"memo": "515624204"
}
}
```
Instruct clients to use the **Message to Beneficiary (OBI)** or **Message to Recipient (OBI)** field for the memo. If unavailable, use the **Memo** field. For international wires, share the `bankSwiftCode`.
### Step 2: View account balances
**`GET /v2/subaccounts/customers/{customerId}/accounts`**
```bash Request theme={null}
curl --request GET \
--url https://api.anchorage-staging.com/v2/subaccounts/customers/{customerId}/accounts \
--header 'Api-Access-Key: [API Key]' \
--header 'accept: application/json'
```
```json Response theme={null}
{
"data": [
{
"subaccountId": "cb80459c-a930-444e-8f17-69ba9d0e122f",
"name": "A1234_John Doe_Strat1",
"customerId": "cf326d89b501d7ff2d1c7b7ffea4bd305a6561b54c9c6158160e17b5aca5cec2",
"fees": [
{ "type": "MANAGEMENT", "rate": 0.01, "startDate": "2025-02-18", "isBillable": true },
{ "type": "CUSTODY", "rate": 0.01, "startDate": "2025-02-18", "isBillable": true }
],
"balances": [
{ "assetType": "BTC", "totalBalance": "100", "availableForWithdrawal": "100", "availableForTrading": "100" },
{ "assetType": "USD", "totalBalance": "100000", "availableForWithdrawal": "100000", "availableForTrading": "100000" }
]
}
]
}
```
### Step 3: Move funds between same-client accounts
**`POST /v2/subaccounts/transactions`**
Only settled funds can be moved. Use `availableForWithdrawal` for the settled balance. Cannot move funds between different end clients.
```bash Request theme={null}
curl --request POST \
--url https://api.anchorage-staging.com/v2/subaccounts/transactions \
--header 'Api-Access-Key: [API Key]' \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--data '{
"transactions": [
{
"sourceSubaccountId": "cb80459c-a930-444e-8f17-69ba9d0e122f",
"destinationSubaccountId": "3eeaf765-0df2-49c9-9e1f-db9cf3e796dd",
"assetType": "USD",
"amount": "1000.00",
"transactionMemo": "USD re-balance",
"idempotentId": "12838927347"
}
]
}'
```
```json Response theme={null}
{
"data": {
"transactionIds": [
{ "transactionId": "c4c4652f-0c07-472c-a7f8-955fbe07775d", "idempotentId": "12838927347" }
]
}
}
```
Use `idempotentId` on bulk account transactions to prevent duplicate submissions.
***
## Withdraw USD
Key considerations before initiating a USD withdrawal:
* External wire fees are covered by Anchorage Digital (subject to change).
* Funds may only be transferred to the account from which they were initially deposited. To send to a different account, that account must be in the end client's name.
### Withdrawal process
Once submitted, a withdrawal moves through this process:
1. **Wealth manager initiates a USD withdrawal via API.**
2. **Anchorage Digital sends a DocuSign to the end client, copying the wealth manager.**
3. **End client reviews and approves the DocuSign.**
4. **Anchorage Digital initiates the wire to the end client's account.**
5. **Withdrawal transaction completes on the ledger.**
### Banks with master/subaccount structures
The following institutions typically use master + subaccount structures (common for investment accounts):
JPMorgan, Morgan Stanley, TD Bank, Vanguard, Merrill Lynch
For these institutions, format the API payload as follows:
* `bankAccountNr`: `"##-##-#####"`
* `bankRoutingNr`: `"#####"`
* `memo`: `"FCC [Client Name], FCC [recipient bank brokerage sub-account number########]"`
### Step 1: Submit a USD withdrawal
**`POST /v2/subaccounts/{subaccountId}/fiat/withdrawals`**
```bash Request theme={null}
curl --request POST \
--url https://api.anchorage-staging.com/v2/subaccounts/{subaccountId}/fiat/withdrawals \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--data '{
"asset": {
"amount": "1000.00",
"assetType": "USD"
},
"customerDetails": {
"beneficiary": {
"accountNumber": "1234567890",
"address": {
"address": "123 Main St",
"address2": "Apt 4B",
"city": "Anytown",
"country": "USA",
"state": "CA",
"zipcode": "90210"
},
"name": "Jane Doe"
},
"financialInstitution": {
"address": {
"address": "123 Main St",
"address2": "Apt 4B",
"city": "Anytown",
"country": "USA",
"state": "CA",
"zipcode": "90210"
},
"code": "ABA",
"id": "routing_id_123",
"name": "Bank of America"
},
"intermediateFinancialInstitution": {
"address": {
"address": "123 Main St",
"address2": "Apt 4B",
"city": "Anytown",
"country": "USA",
"state": "CA",
"zipcode": "90210"
},
"code": "ABA",
"id": "123",
"name": "Bank of America"
},
"memo": "For services rendered"
}
}'
```
Before submitting, confirm the account has sufficient funds and will continue to have sufficient funds while the request is processing. If the available balance falls below what's needed to complete the withdrawal, Anchorage Digital will need to contact the wealth manager before proceeding.
# Onboarding examples
Source: https://docs.anchorage.com/knowledge-base/platform/developers/wealth/wealth-management-onboarding-examples
Reference example payloads for opening every sub-account type, with and without a pre-agreed termsAgreementId.
These are complete example payloads for **`POST /v2/onboarding/subaccounts`**, covering every account type and subtype supported for individual and institutional end clients.
Each account type is shown twice: once for signers who already hold a `termsAgreementId`, and once for signers who still need to accept terms during onboarding. See [Terms and conditions](/knowledge-base/platform/developers/wealth/wealth-management-onboarding-terms-types) for how a `termsAgreementId` is issued, and the Step 6 field tables on [Onboard individuals](/knowledge-base/platform/developers/wealth/wealth-management-onboarding-individuals#step-6-create-the-account) and [Onboard businesses](/knowledge-base/platform/developers/wealth/wealth-management-onboarding-institutions#step-6-create-the-account) for what each field means.
## With termsAgreementId
Use these examples when every program signer has already agreed to terms and conditions and holds a `termsAgreementId`.
```json INDIVIDUAL_TAXABLE theme={null}
{
"name": "SubAccount INDIVIDUAL_TAXABLE",
"externalId": "{{$randomUUID}}",
"submit": true,
"entries": [
{ "key": "legalEntityName", "value": "SubAccount INDIVIDUAL_TAXABLE" },
{ "key": "accountType", "value": "INDIVIDUAL_TAXABLE" },
{ "key": "documentPreferenceAddressDefaultEmail", "value": "kevin.flynn_4@test.com" },
{ "key": "programSignerGroup", "value": [
{ "programSignerFirstName": "Kevin", "programSignerLastName": "Flynn_5", "programSignerEmail": "kevin.flynn_5@test.com", "termsAgreementId": "31e2bccaeaed62c5a4150e28c5841254" }
]
},
{ "key": "programCustomers", "value": [
{ "programCustomerId": "{{individualId1}}", "programCustomerRole": "PRIMARY" }
]
},
{ "key": "beneficiaryGroup", "value": [
{ "beneficiaryType": "SPOUSE", "beneficiaryName": "Test beneficiary", "beneficiaryAllocation": "50" },
{ "beneficiaryType": "CHARITY", "beneficiaryName": "Test beneficiary 2", "beneficiaryAllocation": "50" }
]
},
{ "key": "contingencyBeneficiaryGroup", "value": [
{ "beneficiaryType": "FAMILY_OR_FRIEND", "beneficiaryName": "Test beneficiary 3", "beneficiaryAllocation": "25" },
{ "beneficiaryType": "TRUST", "beneficiaryName": "Test beneficiary 4", "beneficiaryAllocation": "75" }
]
},
{ "key": "fees", "value": [
{ "feeType": "ADVISORY", "feeRate": "0.1" },
{ "feeType": "MANAGEMENT", "feeRate": "0.25", "feeIsBillable": true }
]
}
]
}
```
```json INSTITUTIONAL_TAXABLE theme={null}
{
"name": "SubAccount INSTITUTIONAL_TAXABLE",
"externalId": "{{$randomUUID}}",
"submit": true,
"entries": [
{ "key": "legalEntityName", "value": "SubAccount INSTITUTIONAL_TAXABLE" },
{ "key": "accountType", "value": "INSTITUTIONAL_TAXABLE" },
{ "key": "documentPreferenceAddressDefaultEmail", "value": "kevin.flynn_4@test.com" },
{ "key": "programSignerGroup", "value": [
{ "programSignerFirstName": "Kevin", "programSignerLastName": "Flynn_5", "programSignerEmail": "kevin.flynn_5@test.com", "termsAgreementId": "31e2bccaeaed62c5a4150e28c5841254" },
{ "programSignerFirstName": "Kevin", "programSignerLastName": "Flynn_6", "programSignerEmail": "kevin.flynn_6@test.com", "termsAgreementId": "aa0d01a3309e1f09b2098760e247dc63" }
]
},
{ "key": "programCustomers", "value": [
{ "programCustomerId": "{{institutionId}}", "programCustomerRole": "PRIMARY" }
]
},
{ "key": "beneficiaryGroup", "value": [
{ "beneficiaryType": "SPOUSE", "beneficiaryName": "Test beneficiary", "beneficiaryAllocation": "50" },
{ "beneficiaryType": "CHARITY", "beneficiaryName": "Test beneficiary 2", "beneficiaryAllocation": "50" }
]
},
{ "key": "contingencyBeneficiaryGroup", "value": [
{ "beneficiaryType": "FAMILY_OR_FRIEND", "beneficiaryName": "Test beneficiary 3", "beneficiaryAllocation": "25" },
{ "beneficiaryType": "TRUST", "beneficiaryName": "Test beneficiary 4", "beneficiaryAllocation": "75" }
]
},
{ "key": "fees", "value": [
{ "feeType": "ADVISORY", "feeRate": "0.1" },
{ "feeType": "MANAGEMENT", "feeRate": "0.25", "feeIsBillable": true }
]
}
]
}
```
```json IRA theme={null}
{
"name": "SubAccount IRA",
"externalId": "{{$randomUUID}}",
"submit": true,
"entries": [
{ "key": "legalEntityName", "value": "SubAccount IRA" },
{ "key": "accountType", "value": "IRA" },
{ "key": "documentPreferenceAddressDefaultEmail", "value": "kevin.flynn_4@test.com" },
{ "key": "programSignerGroup", "value": [
{ "programSignerFirstName": "Kevin", "programSignerLastName": "Flynn_5", "programSignerEmail": "kevin.flynn_5@test.com", "termsAgreementId": "31e2bccaeaed62c5a4150e28c5841254" },
{ "programSignerFirstName": "Kevin", "programSignerLastName": "Flynn_6", "programSignerEmail": "kevin.flynn_6@test.com", "termsAgreementId": "aa0d01a3309e1f09b2098760e247dc63" }
]
},
{ "key": "programCustomers", "value": [
{ "programCustomerId": "{{individualId1}}", "programCustomerRole": "PRIMARY" }
]
},
{ "key": "beneficiaryGroup", "value": [
{ "beneficiaryType": "SPOUSE", "beneficiaryName": "Test beneficiary", "beneficiaryAllocation": "50" },
{ "beneficiaryType": "CHARITY", "beneficiaryName": "Test beneficiary 2", "beneficiaryAllocation": "50" }
]
},
{ "key": "contingencyBeneficiaryGroup", "value": [
{ "beneficiaryType": "FAMILY_OR_FRIEND", "beneficiaryName": "Test beneficiary 3", "beneficiaryAllocation": "25" },
{ "beneficiaryType": "TRUST", "beneficiaryName": "Test beneficiary 4", "beneficiaryAllocation": "75" }
]
},
{ "key": "fees", "value": [
{ "feeType": "ADVISORY", "feeRate": "0.1" },
{ "feeType": "MANAGEMENT", "feeRate": "0.25", "feeIsBillable": true }
]
}
]
}
```
```json IRA — ROLLOVER theme={null}
{
"name": "SubAccount IRA ROLLOVER",
"externalId": "{{$randomUUID}}",
"submit": true,
"entries": [
{ "key": "legalEntityName", "value": "SubAccount IRA ROLLOVER" },
{ "key": "accountType", "value": "IRA" },
{ "key": "accountSubtype", "value": "ROLLOVER" },
{ "key": "documentPreferenceAddressDefaultEmail", "value": "kevin.flynn_4@test.com" },
{ "key": "programSignerGroup", "value": [
{ "programSignerFirstName": "Kevin", "programSignerLastName": "Flynn_5", "programSignerEmail": "kevin.flynn_5@test.com", "termsAgreementId": "31e2bccaeaed62c5a4150e28c5841254" },
{ "programSignerFirstName": "Kevin", "programSignerLastName": "Flynn_6", "programSignerEmail": "kevin.flynn_6@test.com", "termsAgreementId": "aa0d01a3309e1f09b2098760e247dc63" }
]
},
{ "key": "programCustomers", "value": [
{ "programCustomerId": "{{individualId1}}", "programCustomerRole": "PRIMARY" }
]
},
{ "key": "beneficiaryGroup", "value": [
{ "beneficiaryType": "SPOUSE", "beneficiaryName": "Test beneficiary", "beneficiaryAllocation": "50" },
{ "beneficiaryType": "CHARITY", "beneficiaryName": "Test beneficiary 2", "beneficiaryAllocation": "50" }
]
},
{ "key": "contingencyBeneficiaryGroup", "value": [
{ "beneficiaryType": "FAMILY_OR_FRIEND", "beneficiaryName": "Test beneficiary 3", "beneficiaryAllocation": "25" },
{ "beneficiaryType": "TRUST", "beneficiaryName": "Test beneficiary 4", "beneficiaryAllocation": "75" }
]
},
{ "key": "fees", "value": [
{ "feeType": "ADVISORY", "feeRate": "0.1" },
{ "feeType": "MANAGEMENT", "feeRate": "0.25", "feeIsBillable": true }
]
}
]
}
```
```json IRA — CONVERSION theme={null}
{
"name": "SubAccount IRA CONVERSION",
"externalId": "{{$randomUUID}}",
"submit": true,
"entries": [
{ "key": "legalEntityName", "value": "SubAccount IRA CONVERSION" },
{ "key": "accountType", "value": "IRA" },
{ "key": "accountSubtype", "value": "CONVERSION" },
{ "key": "documentPreferenceAddressDefaultEmail", "value": "kevin.flynn_4@test.com" },
{ "key": "programSignerGroup", "value": [
{ "programSignerFirstName": "Kevin", "programSignerLastName": "Flynn_5", "programSignerEmail": "kevin.flynn_5@test.com", "termsAgreementId": "31e2bccaeaed62c5a4150e28c5841254" },
{ "programSignerFirstName": "Kevin", "programSignerLastName": "Flynn_6", "programSignerEmail": "kevin.flynn_6@test.com", "termsAgreementId": "aa0d01a3309e1f09b2098760e247dc63" }
]
},
{ "key": "programCustomers", "value": [
{ "programCustomerId": "{{individualId1}}", "programCustomerRole": "PRIMARY" }
]
},
{ "key": "beneficiaryGroup", "value": [
{ "beneficiaryType": "SPOUSE", "beneficiaryName": "Test beneficiary", "beneficiaryAllocation": "50" },
{ "beneficiaryType": "CHARITY", "beneficiaryName": "Test beneficiary 2", "beneficiaryAllocation": "50" }
]
},
{ "key": "contingencyBeneficiaryGroup", "value": [
{ "beneficiaryType": "FAMILY_OR_FRIEND", "beneficiaryName": "Test beneficiary 3", "beneficiaryAllocation": "25" },
{ "beneficiaryType": "TRUST", "beneficiaryName": "Test beneficiary 4", "beneficiaryAllocation": "75" }
]
},
{ "key": "fees", "value": [
{ "feeType": "ADVISORY", "feeRate": "0.1" },
{ "feeType": "MANAGEMENT", "feeRate": "0.25", "feeIsBillable": true }
]
}
]
}
```
```json ROTH theme={null}
{
"name": "SubAccount ROTH",
"externalId": "{{$randomUUID}}",
"submit": true,
"entries": [
{ "key": "legalEntityName", "value": "SubAccount ROTH" },
{ "key": "accountType", "value": "ROTH" },
{ "key": "documentPreferenceAddressDefaultEmail", "value": "kevin.flynn_4@test.com" },
{ "key": "programSignerGroup", "value": [
{ "programSignerFirstName": "Kevin", "programSignerLastName": "Flynn_5", "programSignerEmail": "kevin.flynn_5@test.com", "termsAgreementId": "31e2bccaeaed62c5a4150e28c5841254" },
{ "programSignerFirstName": "Kevin", "programSignerLastName": "Flynn_6", "programSignerEmail": "kevin.flynn_6@test.com", "termsAgreementId": "aa0d01a3309e1f09b2098760e247dc63" }
]
},
{ "key": "programCustomers", "value": [
{ "programCustomerId": "{{individualId1}}", "programCustomerRole": "PRIMARY" }
]
},
{ "key": "beneficiaryGroup", "value": [
{ "beneficiaryType": "SPOUSE", "beneficiaryName": "Test beneficiary", "beneficiaryAllocation": "50" },
{ "beneficiaryType": "CHARITY", "beneficiaryName": "Test beneficiary 2", "beneficiaryAllocation": "50" }
]
},
{ "key": "contingencyBeneficiaryGroup", "value": [
{ "beneficiaryType": "FAMILY_OR_FRIEND", "beneficiaryName": "Test beneficiary 3", "beneficiaryAllocation": "25" },
{ "beneficiaryType": "TRUST", "beneficiaryName": "Test beneficiary 4", "beneficiaryAllocation": "75" }
]
},
{ "key": "fees", "value": [
{ "feeType": "ADVISORY", "feeRate": "0.1" },
{ "feeType": "MANAGEMENT", "feeRate": "0.25", "feeIsBillable": true }
]
}
]
}
```
```json ROTH — ROLLOVER theme={null}
{
"name": "SubAccount ROTH ROLLOVER",
"externalId": "{{$randomUUID}}",
"submit": true,
"entries": [
{ "key": "legalEntityName", "value": "SubAccount ROTH ROLLOVER" },
{ "key": "accountType", "value": "ROTH" },
{ "key": "accountSubtype", "value": "ROLLOVER" },
{ "key": "documentPreferenceAddressDefaultEmail", "value": "kevin.flynn_4@test.com" },
{ "key": "programSignerGroup", "value": [
{ "programSignerFirstName": "Kevin", "programSignerLastName": "Flynn_5", "programSignerEmail": "kevin.flynn_5@test.com", "termsAgreementId": "31e2bccaeaed62c5a4150e28c5841254" },
{ "programSignerFirstName": "Kevin", "programSignerLastName": "Flynn_6", "programSignerEmail": "kevin.flynn_6@test.com", "termsAgreementId": "aa0d01a3309e1f09b2098760e247dc63" }
]
},
{ "key": "programCustomers", "value": [
{ "programCustomerId": "{{individualId1}}", "programCustomerRole": "PRIMARY" }
]
},
{ "key": "beneficiaryGroup", "value": [
{ "beneficiaryType": "SPOUSE", "beneficiaryName": "Test beneficiary", "beneficiaryAllocation": "50" },
{ "beneficiaryType": "CHARITY", "beneficiaryName": "Test beneficiary 2", "beneficiaryAllocation": "50" }
]
},
{ "key": "contingencyBeneficiaryGroup", "value": [
{ "beneficiaryType": "FAMILY_OR_FRIEND", "beneficiaryName": "Test beneficiary 3", "beneficiaryAllocation": "25" },
{ "beneficiaryType": "TRUST", "beneficiaryName": "Test beneficiary 4", "beneficiaryAllocation": "75" }
]
},
{ "key": "fees", "value": [
{ "feeType": "ADVISORY", "feeRate": "0.1" },
{ "feeType": "MANAGEMENT", "feeRate": "0.25", "feeIsBillable": true }
]
}
]
}
```
```json ROTH — CONVERSION theme={null}
{
"name": "SubAccount ROTH CONVERSION",
"externalId": "{{$randomUUID}}",
"submit": true,
"entries": [
{ "key": "legalEntityName", "value": "SubAccount ROTH CONVERSION" },
{ "key": "accountType", "value": "ROTH" },
{ "key": "accountSubtype", "value": "CONVERSION" },
{ "key": "documentPreferenceAddressDefaultEmail", "value": "kevin.flynn_4@test.com" },
{ "key": "programSignerGroup", "value": [
{ "programSignerFirstName": "Kevin", "programSignerLastName": "Flynn_5", "programSignerEmail": "kevin.flynn_5@test.com", "termsAgreementId": "31e2bccaeaed62c5a4150e28c5841254" },
{ "programSignerFirstName": "Kevin", "programSignerLastName": "Flynn_6", "programSignerEmail": "kevin.flynn_6@test.com", "termsAgreementId": "aa0d01a3309e1f09b2098760e247dc63" }
]
},
{ "key": "programCustomers", "value": [
{ "programCustomerId": "{{individualId1}}", "programCustomerRole": "PRIMARY" }
]
},
{ "key": "beneficiaryGroup", "value": [
{ "beneficiaryType": "SPOUSE", "beneficiaryName": "Test beneficiary", "beneficiaryAllocation": "50" },
{ "beneficiaryType": "CHARITY", "beneficiaryName": "Test beneficiary 2", "beneficiaryAllocation": "50" }
]
},
{ "key": "contingencyBeneficiaryGroup", "value": [
{ "beneficiaryType": "FAMILY_OR_FRIEND", "beneficiaryName": "Test beneficiary 3", "beneficiaryAllocation": "25" },
{ "beneficiaryType": "TRUST", "beneficiaryName": "Test beneficiary 4", "beneficiaryAllocation": "75" }
]
},
{ "key": "fees", "value": [
{ "feeType": "ADVISORY", "feeRate": "0.1" },
{ "feeType": "MANAGEMENT", "feeRate": "0.25", "feeIsBillable": true }
]
}
]
}
```
```json JOINT theme={null}
{
"name": "SubAccount JOINT",
"externalId": "{{$randomUUID}}",
"submit": true,
"entries": [
{ "key": "legalEntityName", "value": "SubAccount JOINT" },
{ "key": "accountType", "value": "JOINT" },
{ "key": "documentPreferenceAddressDefaultEmail", "value": "kevin.flynn_4@test.com" },
{ "key": "programSignerGroup", "value": [
{ "programSignerFirstName": "Kevin", "programSignerLastName": "Flynn_5", "programSignerEmail": "kevin.flynn_5@test.com", "termsAgreementId": "31e2bccaeaed62c5a4150e28c5841254" },
{ "programSignerFirstName": "Kevin", "programSignerLastName": "Flynn_6", "programSignerEmail": "kevin.flynn_6@test.com", "termsAgreementId": "aa0d01a3309e1f09b2098760e247dc63" }
]
},
{ "key": "programCustomers", "value": [
{ "programCustomerId": "{{individualId1}}", "programCustomerRole": "PRIMARY" },
{ "programCustomerId": "{{individualId2}}", "programCustomerRole": "SECONDARY" }
]
},
{ "key": "beneficiaryGroup", "value": [
{ "beneficiaryType": "SPOUSE", "beneficiaryName": "Test beneficiary", "beneficiaryAllocation": "50" },
{ "beneficiaryType": "CHARITY", "beneficiaryName": "Test beneficiary 2", "beneficiaryAllocation": "50" }
]
},
{ "key": "contingencyBeneficiaryGroup", "value": [
{ "beneficiaryType": "FAMILY_OR_FRIEND", "beneficiaryName": "Test beneficiary 3", "beneficiaryAllocation": "25" },
{ "beneficiaryType": "TRUST", "beneficiaryName": "Test beneficiary 4", "beneficiaryAllocation": "75" }
]
},
{ "key": "fees", "value": [
{ "feeType": "ADVISORY", "feeRate": "0.1" },
{ "feeType": "MANAGEMENT", "feeRate": "0.25", "feeIsBillable": true }
]
}
]
}
```
```json CUSTODIAL theme={null}
{
"name": "SubAccount CUSTODIAL",
"externalId": "{{$randomUUID}}",
"submit": true,
"entries": [
{ "key": "legalEntityName", "value": "SubAccount CUSTODIAL" },
{ "key": "accountType", "value": "CUSTODIAL" },
{ "key": "documentPreferenceAddressDefaultEmail", "value": "kevin.flynn_4@test.com" },
{ "key": "programSignerGroup", "value": [
{ "programSignerFirstName": "Kevin", "programSignerLastName": "Flynn_5", "programSignerEmail": "kevin.flynn_5@test.com", "termsAgreementId": "31e2bccaeaed62c5a4150e28c5841254" },
{ "programSignerFirstName": "Kevin", "programSignerLastName": "Flynn_6", "programSignerEmail": "kevin.flynn_6@test.com", "termsAgreementId": "aa0d01a3309e1f09b2098760e247dc63" }
]
},
{ "key": "programCustomers", "value": [
{ "programCustomerId": "{{individualId1}}", "programCustomerRole": "PRIMARY" },
{ "programCustomerId": "{{individualId2}}", "programCustomerRole": "SECONDARY" }
]
},
{ "key": "beneficiaryGroup", "value": [
{ "beneficiaryType": "SPOUSE", "beneficiaryName": "Test beneficiary", "beneficiaryAllocation": "50" },
{ "beneficiaryType": "CHARITY", "beneficiaryName": "Test beneficiary 2", "beneficiaryAllocation": "50" }
]
},
{ "key": "contingencyBeneficiaryGroup", "value": [
{ "beneficiaryType": "FAMILY_OR_FRIEND", "beneficiaryName": "Test beneficiary 3", "beneficiaryAllocation": "25" },
{ "beneficiaryType": "TRUST", "beneficiaryName": "Test beneficiary 4", "beneficiaryAllocation": "75" }
]
},
{ "key": "fees", "value": [
{ "feeType": "ADVISORY", "feeRate": "0.1" },
{ "feeType": "MANAGEMENT", "feeRate": "0.25", "feeIsBillable": true }
]
}
]
}
```
## Without termsAgreementId
Use these examples when program signers still need to accept terms and conditions during onboarding.
```json INDIVIDUAL_TAXABLE theme={null}
{
"name": "SubAccount INDIVIDUAL_TAXABLE",
"externalId": "{{$randomUUID}}",
"submit": true,
"entries": [
{ "key": "legalEntityName", "value": "SubAccount INDIVIDUAL_TAXABLE" },
{ "key": "accountType", "value": "INDIVIDUAL_TAXABLE" },
{ "key": "documentPreferenceAddressDefaultEmail", "value": "kevin.flynn_4@test.com" },
{ "key": "programSignerGroup", "value": [
{ "programSignerFirstName": "Kevin", "programSignerLastName": "Flynn_5", "programSignerEmail": "kevin.flynn_5@test.com" }
]
},
{ "key": "programCustomers", "value": [
{ "programCustomerId": "{{individualId1}}", "programCustomerRole": "PRIMARY" }
]
},
{ "key": "beneficiaryGroup", "value": [
{ "beneficiaryType": "SPOUSE", "beneficiaryName": "Test beneficiary", "beneficiaryAllocation": "50" },
{ "beneficiaryType": "CHARITY", "beneficiaryName": "Test beneficiary 2", "beneficiaryAllocation": "50" }
]
},
{ "key": "contingencyBeneficiaryGroup", "value": [
{ "beneficiaryType": "FAMILY_OR_FRIEND", "beneficiaryName": "Test beneficiary 3", "beneficiaryAllocation": "25" },
{ "beneficiaryType": "TRUST", "beneficiaryName": "Test beneficiary 4", "beneficiaryAllocation": "75" }
]
},
{ "key": "fees", "value": [
{ "feeType": "ADVISORY", "feeRate": "0.1" },
{ "feeType": "MANAGEMENT", "feeRate": "0.25", "feeIsBillable": true }
]
}
]
}
```
```json INSTITUTIONAL_TAXABLE theme={null}
{
"name": "SubAccount INSTITUTIONAL_TAXABLE",
"externalId": "{{$randomUUID}}",
"submit": true,
"entries": [
{ "key": "legalEntityName", "value": "SubAccount INSTITUTIONAL_TAXABLE" },
{ "key": "accountType", "value": "INSTITUTIONAL_TAXABLE" },
{ "key": "documentPreferenceAddressDefaultEmail", "value": "kevin.flynn_4@test.com" },
{ "key": "programSignerGroup", "value": [
{ "programSignerFirstName": "Kevin", "programSignerLastName": "Flynn_5", "programSignerEmail": "kevin.flynn_5@test.com" },
{ "programSignerFirstName": "Kevin", "programSignerLastName": "Flynn_6", "programSignerEmail": "kevin.flynn_6@test.com" }
]
},
{ "key": "programCustomers", "value": [
{ "programCustomerId": "{{institutionId}}", "programCustomerRole": "PRIMARY" }
]
},
{ "key": "beneficiaryGroup", "value": [
{ "beneficiaryType": "SPOUSE", "beneficiaryName": "Test beneficiary", "beneficiaryAllocation": "50" },
{ "beneficiaryType": "CHARITY", "beneficiaryName": "Test beneficiary 2", "beneficiaryAllocation": "50" }
]
},
{ "key": "contingencyBeneficiaryGroup", "value": [
{ "beneficiaryType": "FAMILY_OR_FRIEND", "beneficiaryName": "Test beneficiary 3", "beneficiaryAllocation": "25" },
{ "beneficiaryType": "TRUST", "beneficiaryName": "Test beneficiary 4", "beneficiaryAllocation": "75" }
]
},
{ "key": "fees", "value": [
{ "feeType": "ADVISORY", "feeRate": "0.1" },
{ "feeType": "MANAGEMENT", "feeRate": "0.25", "feeIsBillable": true }
]
}
]
}
```
```json IRA theme={null}
{
"name": "SubAccount IRA",
"externalId": "{{$randomUUID}}",
"submit": true,
"entries": [
{ "key": "legalEntityName", "value": "SubAccount IRA" },
{ "key": "accountType", "value": "IRA" },
{ "key": "documentPreferenceAddressDefaultEmail", "value": "kevin.flynn_4@test.com" },
{ "key": "programSignerGroup", "value": [
{ "programSignerFirstName": "Kevin", "programSignerLastName": "Flynn_5", "programSignerEmail": "kevin.flynn_5@test.com" },
{ "programSignerFirstName": "Kevin", "programSignerLastName": "Flynn_6", "programSignerEmail": "kevin.flynn_6@test.com" }
]
},
{ "key": "programCustomers", "value": [
{ "programCustomerId": "{{individualId1}}", "programCustomerRole": "PRIMARY" }
]
},
{ "key": "beneficiaryGroup", "value": [
{ "beneficiaryType": "SPOUSE", "beneficiaryName": "Test beneficiary", "beneficiaryAllocation": "50" },
{ "beneficiaryType": "CHARITY", "beneficiaryName": "Test beneficiary 2", "beneficiaryAllocation": "50" }
]
},
{ "key": "contingencyBeneficiaryGroup", "value": [
{ "beneficiaryType": "FAMILY_OR_FRIEND", "beneficiaryName": "Test beneficiary 3", "beneficiaryAllocation": "25" },
{ "beneficiaryType": "TRUST", "beneficiaryName": "Test beneficiary 4", "beneficiaryAllocation": "75" }
]
},
{ "key": "fees", "value": [
{ "feeType": "ADVISORY", "feeRate": "0.1" },
{ "feeType": "MANAGEMENT", "feeRate": "0.25", "feeIsBillable": true }
]
}
]
}
```
```json IRA — ROLLOVER theme={null}
{
"name": "SubAccount IRA ROLLOVER",
"externalId": "{{$randomUUID}}",
"submit": true,
"entries": [
{ "key": "legalEntityName", "value": "SubAccount IRA ROLLOVER" },
{ "key": "accountType", "value": "IRA" },
{ "key": "accountSubtype", "value": "ROLLOVER" },
{ "key": "documentPreferenceAddressDefaultEmail", "value": "kevin.flynn_4@test.com" },
{ "key": "programSignerGroup", "value": [
{ "programSignerFirstName": "Kevin", "programSignerLastName": "Flynn_5", "programSignerEmail": "kevin.flynn_5@test.com" },
{ "programSignerFirstName": "Kevin", "programSignerLastName": "Flynn_6", "programSignerEmail": "kevin.flynn_6@test.com" }
]
},
{ "key": "programCustomers", "value": [
{ "programCustomerId": "{{individualId1}}", "programCustomerRole": "PRIMARY" }
]
},
{ "key": "beneficiaryGroup", "value": [
{ "beneficiaryType": "SPOUSE", "beneficiaryName": "Test beneficiary", "beneficiaryAllocation": "50" },
{ "beneficiaryType": "CHARITY", "beneficiaryName": "Test beneficiary 2", "beneficiaryAllocation": "50" }
]
},
{ "key": "contingencyBeneficiaryGroup", "value": [
{ "beneficiaryType": "FAMILY_OR_FRIEND", "beneficiaryName": "Test beneficiary 3", "beneficiaryAllocation": "25" },
{ "beneficiaryType": "TRUST", "beneficiaryName": "Test beneficiary 4", "beneficiaryAllocation": "75" }
]
},
{ "key": "fees", "value": [
{ "feeType": "ADVISORY", "feeRate": "0.1" },
{ "feeType": "MANAGEMENT", "feeRate": "0.25", "feeIsBillable": true }
]
}
]
}
```
```json IRA — CONVERSION theme={null}
{
"name": "SubAccount IRA CONVERSION",
"externalId": "{{$randomUUID}}",
"submit": true,
"entries": [
{ "key": "legalEntityName", "value": "SubAccount IRA CONVERSION" },
{ "key": "accountType", "value": "IRA" },
{ "key": "accountSubtype", "value": "CONVERSION" },
{ "key": "documentPreferenceAddressDefaultEmail", "value": "kevin.flynn_4@test.com" },
{ "key": "programSignerGroup", "value": [
{ "programSignerFirstName": "Kevin", "programSignerLastName": "Flynn_5", "programSignerEmail": "kevin.flynn_5@test.com" },
{ "programSignerFirstName": "Kevin", "programSignerLastName": "Flynn_6", "programSignerEmail": "kevin.flynn_6@test.com" }
]
},
{ "key": "programCustomers", "value": [
{ "programCustomerId": "{{individualId1}}", "programCustomerRole": "PRIMARY" }
]
},
{ "key": "beneficiaryGroup", "value": [
{ "beneficiaryType": "SPOUSE", "beneficiaryName": "Test beneficiary", "beneficiaryAllocation": "50" },
{ "beneficiaryType": "CHARITY", "beneficiaryName": "Test beneficiary 2", "beneficiaryAllocation": "50" }
]
},
{ "key": "contingencyBeneficiaryGroup", "value": [
{ "beneficiaryType": "FAMILY_OR_FRIEND", "beneficiaryName": "Test beneficiary 3", "beneficiaryAllocation": "25" },
{ "beneficiaryType": "TRUST", "beneficiaryName": "Test beneficiary 4", "beneficiaryAllocation": "75" }
]
},
{ "key": "fees", "value": [
{ "feeType": "ADVISORY", "feeRate": "0.1" },
{ "feeType": "MANAGEMENT", "feeRate": "0.25", "feeIsBillable": true }
]
}
]
}
```
```json ROTH theme={null}
{
"name": "SubAccount ROTH",
"externalId": "{{$randomUUID}}",
"submit": true,
"entries": [
{ "key": "legalEntityName", "value": "SubAccount ROTH" },
{ "key": "accountType", "value": "ROTH" },
{ "key": "documentPreferenceAddressDefaultEmail", "value": "kevin.flynn_4@test.com" },
{ "key": "programSignerGroup", "value": [
{ "programSignerFirstName": "Kevin", "programSignerLastName": "Flynn_5", "programSignerEmail": "kevin.flynn_5@test.com" },
{ "programSignerFirstName": "Kevin", "programSignerLastName": "Flynn_6", "programSignerEmail": "kevin.flynn_6@test.com" }
]
},
{ "key": "programCustomers", "value": [
{ "programCustomerId": "{{individualId1}}", "programCustomerRole": "PRIMARY" }
]
},
{ "key": "beneficiaryGroup", "value": [
{ "beneficiaryType": "SPOUSE", "beneficiaryName": "Test beneficiary", "beneficiaryAllocation": "50" },
{ "beneficiaryType": "CHARITY", "beneficiaryName": "Test beneficiary 2", "beneficiaryAllocation": "50" }
]
},
{ "key": "contingencyBeneficiaryGroup", "value": [
{ "beneficiaryType": "FAMILY_OR_FRIEND", "beneficiaryName": "Test beneficiary 3", "beneficiaryAllocation": "25" },
{ "beneficiaryType": "TRUST", "beneficiaryName": "Test beneficiary 4", "beneficiaryAllocation": "75" }
]
},
{ "key": "fees", "value": [
{ "feeType": "ADVISORY", "feeRate": "0.1" },
{ "feeType": "MANAGEMENT", "feeRate": "0.25", "feeIsBillable": true }
]
}
]
}
```
```json ROTH — ROLLOVER theme={null}
{
"name": "SubAccount ROTH ROLLOVER",
"externalId": "{{$randomUUID}}",
"submit": true,
"entries": [
{ "key": "legalEntityName", "value": "SubAccount ROTH ROLLOVER" },
{ "key": "accountType", "value": "ROTH" },
{ "key": "accountSubtype", "value": "ROLLOVER" },
{ "key": "documentPreferenceAddressDefaultEmail", "value": "kevin.flynn_4@test.com" },
{ "key": "programSignerGroup", "value": [
{ "programSignerFirstName": "Kevin", "programSignerLastName": "Flynn_5", "programSignerEmail": "kevin.flynn_5@test.com" },
{ "programSignerFirstName": "Kevin", "programSignerLastName": "Flynn_6", "programSignerEmail": "kevin.flynn_6@test.com" }
]
},
{ "key": "programCustomers", "value": [
{ "programCustomerId": "{{individualId1}}", "programCustomerRole": "PRIMARY" }
]
},
{ "key": "beneficiaryGroup", "value": [
{ "beneficiaryType": "SPOUSE", "beneficiaryName": "Test beneficiary", "beneficiaryAllocation": "50" },
{ "beneficiaryType": "CHARITY", "beneficiaryName": "Test beneficiary 2", "beneficiaryAllocation": "50" }
]
},
{ "key": "contingencyBeneficiaryGroup", "value": [
{ "beneficiaryType": "FAMILY_OR_FRIEND", "beneficiaryName": "Test beneficiary 3", "beneficiaryAllocation": "25" },
{ "beneficiaryType": "TRUST", "beneficiaryName": "Test beneficiary 4", "beneficiaryAllocation": "75" }
]
},
{ "key": "fees", "value": [
{ "feeType": "ADVISORY", "feeRate": "0.1" },
{ "feeType": "MANAGEMENT", "feeRate": "0.25", "feeIsBillable": true }
]
}
]
}
```
```json ROTH — CONVERSION theme={null}
{
"name": "SubAccount ROTH CONVERSION",
"externalId": "{{$randomUUID}}",
"submit": true,
"entries": [
{ "key": "legalEntityName", "value": "SubAccount ROTH CONVERSION" },
{ "key": "accountType", "value": "ROTH" },
{ "key": "accountSubtype", "value": "CONVERSION" },
{ "key": "documentPreferenceAddressDefaultEmail", "value": "kevin.flynn_4@test.com" },
{ "key": "programSignerGroup", "value": [
{ "programSignerFirstName": "Kevin", "programSignerLastName": "Flynn_5", "programSignerEmail": "kevin.flynn_5@test.com" },
{ "programSignerFirstName": "Kevin", "programSignerLastName": "Flynn_6", "programSignerEmail": "kevin.flynn_6@test.com" }
]
},
{ "key": "programCustomers", "value": [
{ "programCustomerId": "{{individualId1}}", "programCustomerRole": "PRIMARY" }
]
},
{ "key": "beneficiaryGroup", "value": [
{ "beneficiaryType": "SPOUSE", "beneficiaryName": "Test beneficiary", "beneficiaryAllocation": "50" },
{ "beneficiaryType": "CHARITY", "beneficiaryName": "Test beneficiary 2", "beneficiaryAllocation": "50" }
]
},
{ "key": "contingencyBeneficiaryGroup", "value": [
{ "beneficiaryType": "FAMILY_OR_FRIEND", "beneficiaryName": "Test beneficiary 3", "beneficiaryAllocation": "25" },
{ "beneficiaryType": "TRUST", "beneficiaryName": "Test beneficiary 4", "beneficiaryAllocation": "75" }
]
},
{ "key": "fees", "value": [
{ "feeType": "ADVISORY", "feeRate": "0.1" },
{ "feeType": "MANAGEMENT", "feeRate": "0.25", "feeIsBillable": true }
]
}
]
}
```
```json JOINT theme={null}
{
"name": "SubAccount JOINT",
"externalId": "{{$randomUUID}}",
"submit": true,
"entries": [
{ "key": "legalEntityName", "value": "SubAccount JOINT" },
{ "key": "accountType", "value": "JOINT" },
{ "key": "documentPreferenceAddressDefaultEmail", "value": "kevin.flynn_4@test.com" },
{ "key": "programSignerGroup", "value": [
{ "programSignerFirstName": "Kevin", "programSignerLastName": "Flynn_5", "programSignerEmail": "kevin.flynn_5@test.com" },
{ "programSignerFirstName": "Kevin", "programSignerLastName": "Flynn_6", "programSignerEmail": "kevin.flynn_6@test.com" }
]
},
{ "key": "programCustomers", "value": [
{ "programCustomerId": "{{individualId1}}", "programCustomerRole": "PRIMARY" },
{ "programCustomerId": "{{individualId2}}", "programCustomerRole": "SECONDARY" }
]
},
{ "key": "beneficiaryGroup", "value": [
{ "beneficiaryType": "SPOUSE", "beneficiaryName": "Test beneficiary", "beneficiaryAllocation": "50" },
{ "beneficiaryType": "CHARITY", "beneficiaryName": "Test beneficiary 2", "beneficiaryAllocation": "50" }
]
},
{ "key": "contingencyBeneficiaryGroup", "value": [
{ "beneficiaryType": "FAMILY_OR_FRIEND", "beneficiaryName": "Test beneficiary 3", "beneficiaryAllocation": "25" },
{ "beneficiaryType": "TRUST", "beneficiaryName": "Test beneficiary 4", "beneficiaryAllocation": "75" }
]
},
{ "key": "fees", "value": [
{ "feeType": "ADVISORY", "feeRate": "0.1" },
{ "feeType": "MANAGEMENT", "feeRate": "0.25", "feeIsBillable": true }
]
}
]
}
```
```json CUSTODIAL theme={null}
{
"name": "SubAccount CUSTODIAL",
"externalId": "{{$randomUUID}}",
"submit": true,
"entries": [
{ "key": "legalEntityName", "value": "SubAccount CUSTODIAL" },
{ "key": "accountType", "value": "CUSTODIAL" },
{ "key": "documentPreferenceAddressDefaultEmail", "value": "kevin.flynn_4@test.com" },
{ "key": "programSignerGroup", "value": [
{ "programSignerFirstName": "Kevin", "programSignerLastName": "Flynn_5", "programSignerEmail": "kevin.flynn_5@test.com" },
{ "programSignerFirstName": "Kevin", "programSignerLastName": "Flynn_6", "programSignerEmail": "kevin.flynn_6@test.com" }
]
},
{ "key": "programCustomers", "value": [
{ "programCustomerId": "{{individualId1}}", "programCustomerRole": "PRIMARY" },
{ "programCustomerId": "{{individualId2}}", "programCustomerRole": "SECONDARY" }
]
},
{ "key": "beneficiaryGroup", "value": [
{ "beneficiaryType": "SPOUSE", "beneficiaryName": "Test beneficiary", "beneficiaryAllocation": "50" },
{ "beneficiaryType": "CHARITY", "beneficiaryName": "Test beneficiary 2", "beneficiaryAllocation": "50" }
]
},
{ "key": "contingencyBeneficiaryGroup", "value": [
{ "beneficiaryType": "FAMILY_OR_FRIEND", "beneficiaryName": "Test beneficiary 3", "beneficiaryAllocation": "25" },
{ "beneficiaryType": "TRUST", "beneficiaryName": "Test beneficiary 4", "beneficiaryAllocation": "75" }
]
},
{ "key": "fees", "value": [
{ "feeType": "ADVISORY", "feeRate": "0.1" },
{ "feeType": "MANAGEMENT", "feeRate": "0.25", "feeIsBillable": true }
]
}
]
}
```
# Onboard individuals
Source: https://docs.anchorage.com/knowledge-base/platform/developers/wealth/wealth-management-onboarding-individuals
Onboard individual end clients and open their accounts via the Anchorage Digital API.
Open a crypto account for an individual end client. If they're new to your platform, onboard them first, then open their account. If they already have a `customerId`, skip straight to opening the account.
## How it works
Look up whether this individual already has a `customerId` with Anchorage Digital. Existing clients can open additional accounts without repeating onboarding.
Submit the client's KYC information and documentation, and collect their agreement to your terms and conditions. Anchorage Digital performs due diligence and returns a `customerId`.
Create an account (subaccount) for the client, specifying the account type and linking it to their `customerId` — either the one just created, or an existing one.
Check the account's status, or subscribe to the `subaccount.opened` webhook, to know when it's active.
You don't need to wait for a new client's onboarding to be fully approved before opening their account — you can submit the account application right after receiving their `customerId`. Client onboarding and account opening are approved together.
This flow supports opening every individual account type — see the account types table in [Step 6](#step-6-create-the-account) for the full list.
Before onboarding your first client, decide how you'll deliver terms and conditions and whether you're using a KYC reliance model — see [Terms and conditions](/knowledge-base/platform/developers/wealth/wealth-management-onboarding-terms-types).
***
## Integration steps
If this client already has a `customerId`, skip ahead to [Step 6: Create the account](#step-6-create-the-account).
### Step 1: Onboard the client
**`POST /v2/onboarding/customers`**
* `applicationType`: `RIA_PC_INDIVIDUAL`
* `externalId`: unique identifier used by the wealth platform to identify this end client
* `entries`: see table below
**Sandbox:** applications must use mock data and reviews are expedited. **Production:** actual client information is required and a more thorough review process applies — no mock data is permitted in production.
| **Tag** | **Description** | **Required** | **Type** | **Value restrictions** |
| :------------------------------------ | :------------------------------------ | :--------------------------------------------------------------------- | :------- | :---------------------------------------- |
| legalEntityName | legal entity name | Yes | String | |
| programCustomer | list of end clients | Yes | Array | 1 entry |
| programCustomer/firstName | end client first name | Yes | String | limited to 36 characters |
| programCustomer/lastName | end client last name | Yes | String | limited to 48 characters |
| programCustomer/middleName | end client middle name | No | String | |
| programCustomer/dateOfBirth | end client date of birth | Yes | Date | ISO 8601 date (without time) |
| programCustomer/email | end client email address | Yes | String | valid e-mail address |
| programCustomer/ssn | end client social security number | Yes (this or `governmentId` required) | String | 9-digit number |
| programCustomer/governmentId | end client government-specific ID | Yes (this or `ssn` required) | String | |
| programCustomer/physicalCountry | end client country | Yes | String | ISO 3166-1 alpha-2 country code |
| programCustomer/physicalStreetAddress | end client street address | Yes | String | |
| programCustomer/physicalCity | end client city name | Yes | String | |
| programCustomer/physicalStateUS | end client US state | Yes, for US country | String | 2-character USPS state code |
| programCustomer/physicalStateOther | end client non-US state or province | Yes, for non-US countries | String | |
| programCustomer/physicalPostalCode | end client zip code or postal code | Yes | String | |
| programCustomer/idType | end client type of ID uploaded | Yes | Enum | `GOVERNMENT_ISSUED_ID_CARD` or `PASSPORT` |
| certifiedW9 | customer has signed W-9 certification | Yes if `programCustomer/ssn` is provided (US individuals) | Boolean | `true` or `false` |
| certifiedW8 | customer has signed W-8 certification | Yes if `programCustomer/governmentId` is provided (non-US individuals) | Boolean | `true` or `false` |
A unique `customerId` is returned, which is used in all future calls to identify this end client.
```json Request — non-US individual (W-8) theme={null}
{
"applicationType": "RIA_PC_INDIVIDUAL",
"entries": [
{ "key": "legalEntityName", "value": "RIA PC Inv 1 Test" },
{
"key": "programCustomer",
"value": {
"firstName": "Kevin",
"lastName": "Flynn_1",
"dateOfBirth": "01/01/1970",
"email": "kevin.flynn_1@test.com",
"governmentId": "123456789",
"physicalCity": "city",
"physicalCountry": "FRANCE",
"physicalPostalCode": "7500",
"physicalStateOther": "Paris",
"physicalStreetAddress": "123 Lightcycle Way",
"idType": "GOVERNMENT_ISSUED_ID_CARD"
}
},
{ "key": "certifiedW8", "value": true }
]
}
```
```json Request — US individual (W-9) theme={null}
{
"applicationType": "RIA_PC_INDIVIDUAL",
"entries": [
{ "key": "legalEntityName", "value": "RIA PC Inv 1 Test" },
{
"key": "programCustomer",
"value": {
"firstName": "Kevin",
"lastName": "Flynn_1",
"dateOfBirth": "01/01/1970",
"email": "kevin.flynn_1@test.com",
"ssn": "123456789",
"physicalCity": "city",
"physicalCountry": "US",
"physicalPostalCode": "94104",
"physicalStateUS": "CA",
"physicalStreetAddress": "123 Lightcycle Way",
"idType": "GOVERNMENT_ISSUED_ID_CARD"
}
},
{ "key": "certifiedW9", "value": true }
]
}
```
```json Response theme={null}
{
"data": {
"customerId": "c78e4bbd8f346e1f314f160ef3c84e69d2d1cbc878e569137eba688a1cf56ea1",
"status": "IN_PROGRESS"
}
}
```
### Step 2: Upload required documents
**`POST /v2/onboarding/customers/{{customerId}}/document`**
| **Tag** | **Description** | **Required** | **Type** | **Value restrictions** |
| :----------- | :------------------------------ | :------------------------------- | :------- | :--------------------------------- |
| documentType | passport | Yes, if ID card is not provided | Upload | GIF, JPEG, PNG, or PDF — max 25 MB |
| documentType | government-issued ID card front | Yes, if passport is not provided | Upload | GIF, JPEG, PNG, or PDF — max 25 MB |
| documentType | government-issued ID card back | Yes, if passport is not provided | Upload | GIF, JPEG, PNG, or PDF — max 25 MB |
Upload a single image file (GIF, JPEG, PNG, or PDF). If a second file is uploaded, the latest replaces the first. Multi-file archives are rejected. A signed upload URL is returned and accepts the document via a PUT request. The URL is valid for 15 minutes — if it expires, request a new one by calling this endpoint again.
```json Request theme={null}
{
"documentType": "programCustomer.idCardFront"
}
```
```json Response theme={null}
{
"data": {
"url": "https://storage.googleapis.com/anchorage/pii/v1/{{customerId}}/ID_CARD_FRONT/{{documentId}}?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Expires=899&X-Goog-Signature={{signature}}"
}
}
```
Upload the image to the returned URL:
```bash theme={null}
curl -X PUT -H 'Content-Type: application/octet-stream' --data-binary @image.png {{step2url.response.body.data.url}}
```
### Step 3: Check onboarding status
**`GET /v2/onboarding/customers/{{customerId}}`**
Any errors or missing documents are listed in the `errors` section of the response.
```json Response theme={null}
{
"data": {
"customerId": "c78e4bbd8f346e1f314f160ef3c84e69d2d1cbc878e569137eba688a1cf56ea1",
"entries": [
{
"key": "programCustomer",
"value": [
{
"dateOfBirth": "01/01/1970",
"email": "kevin.flynn_1@test.com",
"firstName": "Kevin",
"idCardBack": "866b68b4a99de75dd9bca11d231041a7bd4e2469bc488abf5d6614283917b34c",
"idCardFront": "55c7e1dc053fdd522470040e59a448cb3ad9593dd169729cee27660ae95466c4",
"idType": "GOVERNMENT_ISSUED_ID_CARD",
"lastName": "Flynn_1",
"physicalCity": "city",
"physicalCountry": "US",
"physicalPostalCode": "94104",
"physicalStateUS": "CA",
"physicalStreetAddress": "123 Lightcycle Way",
"ssn": "123456789"
}
]
},
{ "key": "legalEntityName", "value": "RIA PC Inv 1 Test" }
],
"errors": [
{ "key": "programCustomer.idCardFront", "status": "MISSING", "value": "expected 1 answer for non-void triggered question, instead got 0" },
{ "key": "programCustomer.idCardBack", "status": "MISSING", "value": "expected 1 answer for non-void triggered question, instead got 0" }
],
"status": "IN_PROGRESS"
}
}
```
### Step 4: Submit the client application
**`POST /v2/onboarding/customers/{{customerId}}/submit`**
Once submitted, you can move on to opening the account — you don't need to wait for approval first (see the note above).
### Step 5: Check client approval status
**`GET /v2/onboarding/customers/{{customerId}}`**
Upon successful submission, status changes from `IN_PROGRESS` to `IN_REVIEW`. Once fully approved, status changes to `COMPLETE`. To receive asynchronous notification when approval completes, register for webhooks — see [Configure webhooks](/knowledge-base/platform/developers/webhooks/webhooks-configure).
### Step 6: Create the account
**`POST /v2/onboarding/subaccounts`**
Supported individual account types:
| Account type | Subtype | End client(s) |
| :------------------- | :----------- | :------------ |
| `IRA` | — | 1 |
| `IRA` | `ROLLOVER` | 1 |
| `IRA` | `CONVERSION` | 1 |
| `ROTH` | — | 1 |
| `ROTH` | `ROLLOVER` | 1 |
| `ROTH` | `CONVERSION` | 1 |
| `JOINT` | — | 2 |
| `CUSTODIAL` | — | 2 |
| `INDIVIDUAL_TAXABLE` | — | 1 |
Expected program signers by account type:
| Account type | Expected program signers |
| :------------------- | :------------------------------------------ |
| `IRA` | Linked end client who owns the account |
| `ROTH` | Linked end client who owns the account |
| `JOINT` | Both linked end clients who own the account |
| `CUSTODIAL` | Parent end client, not the child |
| `INDIVIDUAL_TAXABLE` | Linked end client who owns the account |
Key fields:
| Field | Description | Required | Type | Restrictions |
| :------------------------------------------ | :----------------------------------------------- | :---------------------------------------- | :------ | :---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `legalEntityName` | Legal entity name | Yes | String | |
| `accountType` | Account type | Yes | Enum | See table above |
| `accountSubtype` | Account subtype | Only for `IRA` or `ROTH` | Enum | `ROLLOVER` or `CONVERSION` |
| `programSignerGroup` | List of program signers | Yes | Array | |
| `programSignerGroup/programSignerFirstName` | First name | Yes | String | |
| `programSignerGroup/programSignerLastName` | Last name | Yes | String | |
| `programSignerGroup/programSignerEmail` | Email | Yes | String | Valid email |
| `documentPreferenceAddressDefaultEmail` | Statement delivery email(s) | Yes | String | Comma-separated valid emails |
| `termsAgreementID` | Terms agreement ID | If T\&Cs enabled | String | ID from `/v2/onboarding/agreements/terms` — see [Terms and conditions](/knowledge-base/platform/developers/wealth/wealth-management-onboarding-terms-types) |
| `beneficiaryGroup` | Beneficiaries | No | Array | |
| `beneficiaryGroup/beneficiaryType` | Type | Yes | Enum | `SPOUSE`, `FAMILY_OR_FRIEND`, `CHARITY`, `TRUST`, `ESTATE` |
| `beneficiaryGroup/beneficiaryName` | Name | Yes | String | |
| `beneficiaryGroup/beneficiaryAllocation` | Allocation % | Yes, must sum to 100 | Number | 1–100 |
| `contingencyBeneficiaryGroup` | Contingency beneficiaries | No | Array | Same structure as `beneficiaryGroup` |
| `fees` | Fee configuration | No | Array | See [fee types](/knowledge-base/platform/developers/wealth/wealth-management-subaccounts#fee-types) |
| `isSegregated` | Wallet structure (omnibus or segregated wallets) | No, defaults to `false` (omnibus wallets) | Boolean | Org must opt into feature |
| `programCustomers` | Linked end clients | Yes | Array | |
| `programCustomers/programCustomerId` | End client ID | Yes | String | The `customerId` from Step 1 — or an existing client's `customerId` if you skipped onboarding |
| `programCustomers/programCustomerRole` | Role | Yes | Enum | `PRIMARY` or `SECONDARY` |
| `submit` | Submit immediately | No, defaults to `false` | Boolean | |
Each account requires a signer who can represent the client. The signer can be the end client themselves or another authorized individual.
```json Example request theme={null}
{
"name": "{{name}}",
"externalId": "{{externalId}}",
"submit": true,
"entries": [
{ "key": "legalEntityName", "value": "SubAccount IRA ROLLOVER" },
{ "key": "accountType", "value": "IRA" },
{ "key": "accountSubtype", "value": "ROLLOVER" },
{ "key": "isSegregated", "value": true },
{ "key": "documentPreferenceAddressDefaultEmail", "value": "kevin.flynn_4@test.com" },
{ "key": "programSignerGroup", "value": [
{ "programSignerFirstName": "Kevin", "programSignerLastName": "Flynn_5", "programSignerEmail": "kevin.flynn_5@test.com" },
{ "programSignerFirstName": "Kevin", "programSignerLastName": "Flynn_6", "programSignerEmail": "kevin.flynn_6@test.com" }
]
},
{ "key": "programCustomers", "value": [
{ "programCustomerId": "{{customerId1}}", "programCustomerRole": "PRIMARY" }
]
},
{ "key": "beneficiaryGroup", "value": [
{ "beneficiaryType": "SPOUSE", "beneficiaryName": "Test beneficiary", "beneficiaryAllocation": "50" },
{ "beneficiaryType": "CHARITY", "beneficiaryName": "Test beneficiary 2", "beneficiaryAllocation": "50" }
]
},
{ "key": "contingencyBeneficiaryGroup", "value": [
{ "beneficiaryType": "FAMILY_OR_FRIEND", "beneficiaryName": "Test beneficiary 3", "beneficiaryAllocation": "25" },
{ "beneficiaryType": "TRUST", "beneficiaryName": "Test beneficiary 4", "beneficiaryAllocation": "75" }
]
},
{ "key": "fees", "value": [
{ "feeType": "ADVISORY", "feeRate": "0.1" },
{ "feeType": "MANAGEMENT", "feeRate": "0.25", "feeIsBillable": true }
]
}
]
}
```
A unique `subaccountId` is returned for all future references to this account.
Every account type follows this same payload shape — only `accountType`, `accountSubtype` (where applicable), and the number of `programCustomers` entries change, per the table above. Add `termsAgreementId` to a program signer's entry only if [terms and conditions delivery](/knowledge-base/platform/developers/wealth/wealth-management-onboarding-terms-types) requires their explicit agreement. See [Onboarding examples](/knowledge-base/platform/developers/wealth/wealth-management-onboarding-examples) for complete request payloads, with and without a `termsAgreementId`, for every account type.
### Step 7: List account applications
**`GET /v2/onboarding/subaccounts`**
Returns all account onboarding applications associated with this API key. Supports `afterId` and `limit` for cursor pagination.
### Step 8: Check account status
**`GET /v2/onboarding/subaccounts/{subaccountId}`**
Errors and missing documents are listed in the `errors` array of the response.
### Step 9: Update the account application (if errors are present)
**`PUT /v2/onboarding/subaccounts/{subaccountId}`**
Uses the same `entries` array shape as Step 6. Only include the entries you want to change — omitted fields keep their existing value.
```json Example request theme={null}
{
"entries": [
{ "key": "documentPreferenceAddressDefaultEmail", "value": "kevin.flynn_4-updated@test.com" }
]
}
```
Any change to a client's data, or a request to terminate their account, is authenticated by Anchorage Digital Bank with the end client via DocuSign before processing.
### Step 10: Submit the account application (if `submit: false`)
**`POST /v2/onboarding/subaccounts/{subaccountId}/submit`**
### Step 11: Check account approval status
**`GET /v2/subaccounts/customers/accounts?subaccountIds={subaccountId}`**
Status values: `PENDING` (received, awaiting approval) → `OPEN` (approved and active). Alternatively, subscribe to the `subaccount.opened` webhook event for asynchronous notification.
```json Example response (approved) theme={null}
{
"data": {
"applicationId": "6ba46417-66dc-424e-8e68-4fbd2597d993",
"entries": [
{ "key": "programSignerGroup", "value": [
{ "programSignerFirstName": "Kevin", "programSignerLastName": "Flynn_5", "programSignerEmail": "kevin.flynn_5@test.com" },
{ "programSignerFirstName": "Kevin", "programSignerLastName": "Flynn_6", "programSignerEmail": "kevin.flynn_6@test.com" }
]
},
{ "key": "programCustomers", "value": [
{ "programCustomerId": "43a37de2dcc326579fe9ab3a187c48b786007bd759802dfa04ef1aa35383a273", "programCustomerRole": "PRIMARY" }
]
},
{ "key": "accountSubtype", "value": "ROLLOVER" },
{ "key": "accountType", "value": "IRA" },
{ "key": "beneficiaryGroup", "value": [
{ "beneficiaryAllocation": "50", "beneficiaryName": "Test beneficiary", "beneficiaryRelation": "Primary", "beneficiaryType": "Spouse" },
{ "beneficiaryAllocation": "50", "beneficiaryName": "Test beneficiary 2", "beneficiaryRelation": "Contingency", "beneficiaryType": "Charity" }
]
},
{ "key": "fees", "value": [
{ "feeRate": "0.1", "feeType": "Advisory" },
{ "feeIsBillable": "Yes", "feeRate": "0.25", "feeType": "Management" }
]
},
{ "key": "documentPreferenceAddressDefaultEmail", "value": "gareth.test_3@test.com" },
{ "key": "legalEntityName", "value": "SubAccount IRA ROLLOVER" }
],
"errors": [],
"status": "COMPLETE"
}
}
```
***
## Reliance only: edit client information
RIAs with full or partial KYC reliance have access to a flow in which program customers are auto-approved. For these RIAs, select fields remain editable even after application status is `COMPLETE`.
| **Tag** | **Description** | **Required** | **Can edit** | **Type** | **Value restrictions** |
| :------------------------------------ | :------------------------------------ | :------------------------------------------------ | :----------- | :------- | :---------------------------------------- |
| legalEntityName | legal entity name | Yes | No | String | |
| programCustomer | list of end clients | Yes | Yes | Array | 1 entry |
| programCustomer/firstName | end client first name | Yes | Yes | String | limited to 36 characters |
| programCustomer/lastName | end client last name | Yes | Yes | String | limited to 48 characters |
| programCustomer/middleName | end client middle name | No | Yes | String | |
| programCustomer/dateOfBirth | end client date of birth | Yes | No | Date | ISO 8601 date (without time) |
| programCustomer/email | end client email address | Yes | Yes | String | valid e-mail address |
| programCustomer/ssn | end client social security number | Yes (this or `governmentId` required) | No | String | 9-digit number |
| programCustomer/governmentId | end client government-specific ID | Yes (this or `ssn` required) | No | String | |
| programCustomer/physicalCountry | end client country | Yes | Yes | String | ISO 3166-1 alpha-2 country code |
| programCustomer/physicalStreetAddress | end client street address | Yes | Yes | String | |
| programCustomer/physicalCity | end client city name | Yes | Yes | String | |
| programCustomer/physicalStateUS | end client US state | Yes, for US country | Yes | String | 2-character USPS state code |
| programCustomer/physicalStateOther | end client non-US state or province | Yes, for non-US countries | Yes | String | |
| programCustomer/physicalPostalCode | end client zip code or postal code | Yes | Yes | String | |
| programCustomer/idType | end client type of ID uploaded | Yes | No | Enum | `GOVERNMENT_ISSUED_ID_CARD` or `PASSPORT` |
| certifiedW9 | customer has signed W-9 certification | Yes if `programCustomer/ssn` is provided | No | Boolean | `true` or `false` |
| certifiedW8 | customer has signed W-8 certification | Yes if `programCustomer/governmentId` is provided | No | Boolean | `true` or `false` |
# Onboard businesses
Source: https://docs.anchorage.com/knowledge-base/platform/developers/wealth/wealth-management-onboarding-institutions
Onboard business end clients and open their accounts via the Anchorage Digital API.
Open a crypto account for a business end client. If they're new to your platform, onboard them first, then open their account. If they already have a `customerId`, skip straight to opening the account.
## How it works
Look up whether this business already has a `customerId` with Anchorage Digital. Existing clients can open additional accounts without repeating onboarding.
Submit the business's KYB information and documentation, and collect their agreement to your terms and conditions. Anchorage Digital performs due diligence and returns a `customerId`.
Create an account (subaccount) for the client, specifying the account type and linking it to their `customerId` — either the one just created, or an existing one.
Check the account's status, or subscribe to the `subaccount.opened` webhook, to know when it's active.
You don't need to wait for a new client's onboarding to be fully approved before opening their account — you can submit the account application right after receiving their `customerId`. Client onboarding and account opening are approved together.
This flow supports opening a business taxable account (e.g., LLC, C Corp, Trust, etc.) for business end clients.
Before onboarding your first client, decide how you'll deliver terms and conditions and whether you're using a KYC reliance model — see [Terms and conditions](/knowledge-base/platform/developers/wealth/wealth-management-onboarding-terms-types).
***
## Integration steps
If this client already has a `customerId`, skip ahead to [Step 6: Create the account](#step-6-create-the-account).
### Step 1: Onboard the client
**`POST /v2/onboarding/customers`**
* `applicationType`: `RIA_PC_INSTITUTION`
* `externalId`: unique identifier used by the wealth platform to identify this end client
* `entries`: see tables below
**Sandbox:** applications must use mock data and reviews are expedited. **Production:** actual client information is required and a more thorough review process applies — no mock data is permitted in production.
**General entries:**
| **Tag** | **Description** | **Required** | **Type** | **Value restrictions** |
| :------------------------- | :------------------------------------------------------- | :-------------------------------------------------- | :------- | :---------------------------------------------------------------------------------- |
| legalEntityName | legal entity name | Yes | String | |
| hasDbaName | does the organization have a registered DBA name? | Yes | Boolean | `true` or `false` |
| dbaNames | DBA name | Yes, if `hasDbaName` is `true` | String | |
| businessRegistrationNumber | business registration number | Yes (this or `taxId` required) | String | |
| taxId | EIN | Yes (this or `businessRegistrationNumber` required) | Number | 9-digit number |
| proofOfAddressContext | explanation when `hasProofOfAddress` is `false` | No | String | |
| legalStructure | legal structure of the business | No | Enum | `C_CORP`; `LLC`; `LLP`; `LP`; `S_CORP`; `SOLE_PROP`; `TRUST`; `NON_PROFIT`; `OTHER` |
| legalStructureOther | legal structure when `legalStructure` is `OTHER` | No | String | |
| physicalCountry | country | Yes | String | ISO 3166-1 alpha-2 country code |
| physicalStreetAddress | street address | Yes | String | |
| physicalCity | city name | Yes | String | |
| physicalStateUS | US state | Yes, for US country | String | 2-character USPS state code |
| physicalStateOther | non-US state or province | Yes, for non-US countries | String | |
| physicalPostalCode | zip code or postal code | Yes | String | |
| hasProofOfAddress | can you provide a proof of address? | Yes | Boolean | `true` or `false` |
| hasProofOfAddressContext | additional context if unable to provide proof of address | No | String | |
**Additional entries for IRS reporting requirements (US and non-US entities):**
| **Tag** | **Description** | **Required** | **Type** | **Value restrictions** |
| :-------------------------- | :---------------------------------------------------------------- | :----------------------------------------------------------------------------------------------------------------------- | :------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **US entity** | | | | |
| taxClassificationUs | tax classification (entity type) | Yes if `taxId` is provided | Enum | See [tax classification values](#tax-classification-and-fatca-values) below |
| taxExemptionPayeeCode | exempt payee code | No | Enum | `TAX_EXEMPT_PAYEE_CODE_1` through `TAX_EXEMPT_PAYEE_CODE_13`. [Values](https://www.sec.gov/Archives/edgar/data/896923/000120677416006118/exhibit99_a1-vi.htm) |
| fatcaExemptionReportingCode | exemption from FATCA reporting code | No | Enum | See [FATCA values](#tax-classification-and-fatca-values) below |
| certifiedW9 | customer has signed W-9 certification | Yes if `taxId` is provided | Boolean | `true` or `false` |
| **Non-US entity** | | | | |
| taxClassificationNonUs | tax classification (entity type) | Yes if `businessRegistrationNumber` is provided | Enum | See [tax classification values](#tax-classification-and-fatca-values) below |
| disregardedEntityName | disregarded entity name | Yes if `taxClassificationNonUs` is `DISREGARDED_ENTITY` | String | |
| fatcaEntityType | FATCA entity type | Yes if `taxClassificationNonUs` is `DISREGARDED_ENTITY` | Enum | See [FATCA values](#tax-classification-and-fatca-values) below |
| fatcaStatusFfi | FATCA status | Yes if `fatcaEntityType` is `FFI` | Enum | See [FATCA values](#tax-classification-and-fatca-values) below |
| fatcaStatusNffe | FATCA status | Yes if `fatcaEntityType` is `NFFE` | Enum | See [FATCA values](#tax-classification-and-fatca-values) below |
| fatcaStatusExemptBO | FATCA status | Yes if `fatcaEntityType` is `EXEMPTBO` | Enum | See [FATCA values](#tax-classification-and-fatca-values) below |
| giin | GIIN | Yes if `fatcaStatusFfi` is `REPORTING_MODEL_1`, `REPORTING_MODEL_2`, or `REGISTERED_DEEMED_COMPLIANT_OTHER_THAN_MODEL_1` | String | See [GIIN composition](https://www.irs.gov/businesses/corporations/fatca-registration-and-ffi-list-giin-composition-information) |
| beneficialOwnersRequired | any individuals directly or indirectly owning ≥25% of the entity? | Yes if `fatcaStatusNffe` is `PASSIVE` | Boolean | |
| beneficiaryFirstName | beneficiary's legal first name | Yes if `beneficialOwnersRequired` is `true` | String | |
| beneficiaryLastName | beneficiary's legal last name | Yes if `beneficialOwnersRequired` is `true` | String | |
| beneficiaryTaxId | beneficiary's US taxpayer ID number | Yes if `beneficialOwnersRequired` is `true` | String | 9-digit number |
| beneficiaryAllocation | beneficiary's percentage of ownership | Yes if `beneficialOwnersRequired` is `true` | String | 1–100, no percentage sign or spaces (e.g., `35`) |
| beneficiaryCountry | beneficiary's residential country | Yes if `beneficialOwnersRequired` is `true` | String | ISO 3166-1 alpha-2 country code |
| beneficiaryStreetAddress | beneficiary's residential street address | Yes if `beneficialOwnersRequired` is `true` | String | |
| beneficiaryCity | beneficiary's residential city | Yes if `beneficialOwnersRequired` is `true` | String | |
| beneficiaryStateUS | beneficiary's residential state | Yes, for US country | String | 2-character USPS state code |
| beneficiaryStateOther | beneficiary's residential state/province | Yes, for non-US countries | String | |
| beneficiaryPostalCode | beneficiary's zip code or postal code | Yes if `beneficialOwnersRequired` is `true` | String | |
| certifiedW8 | customer has signed W-8 certification | Yes if `businessRegistrationNumber` is provided | Boolean | `true` or `false` |
### Tax classification and FATCA values
| Code | Label |
| :---------------- | :------------------ |
| `C_CORP` | C Corporation |
| `LLC_C_CORP` | LLC - C Corporation |
| `LLC_PARTNERSHIP` | LLC - Partnership |
| `LLC_S_CORP` | LLC - S Corporation |
| `PARTNERSHIP` | Partnership |
| `S_CORP` | S Corporation |
| `TRUST_ESTATE` | Trust/Estate |
| `OTHER` | Other |
| Code | Label |
| :------------------------------------- | :------------------------------------- |
| `CENTRAL_BANK` | Central bank of issue |
| `COMPLEX_TRUST` | Complex trust |
| `CORP` | Corporation |
| `DISREGARDED_ENTITY` | Disregarded entity |
| `ESTATE` | Estate |
| `FOREIGN_GOVERNMENT_CONTROLLED_ENTITY` | Foreign government – controlled entity |
| `FOREIGN_GOVERNMENT_INTEGRAL_PART` | Foreign government – integral part |
| `GRANTOR_TRUST` | Grantor trust |
| `INTERNATIONAL_ORGANIZATION` | International organization |
| `PARTNERSHIP` | Partnership |
| `PRIVATE_FOUNDATION` | Private foundation |
| `SIMPLE_TRUST` | Simple trust |
| `TAX_EXEMPT_ORGANIZATION` | Tax-exempt organization |
| Code | Description |
| :------------------------------ | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `FATCA_EXEMPT_REPORTING_CODE_A` | An organization exempt from tax under section 501(a) or any individual retirement plan as defined in section 701(a)(37) |
| `FATCA_EXEMPT_REPORTING_CODE_B` | The United States or any of its agencies or instrumentalities |
| `FATCA_EXEMPT_REPORTING_CODE_C` | A state, the District of Columbia, a U.S. commonwealth or territory, or any of their political subdivisions or instrumentalities |
| `FATCA_EXEMPT_REPORTING_CODE_D` | A corporation the stock of which is regularly traded on one or more established securities markets, as described in Regulations section 1.1472-1(c)(1)(i) |
| `FATCA_EXEMPT_REPORTING_CODE_E` | A corporation that is a member of the same expanded affiliated group as a corporation described in Regulations section 1.1472-1(c)(1)(i) |
| `FATCA_EXEMPT_REPORTING_CODE_F` | A dealer in securities, commodities, or derivative financial instruments (including notional principal contracts, futures, forwards, and options) that is registered as such under the laws of the United States or any state |
| `FATCA_EXEMPT_REPORTING_CODE_G` | A real estate investment trust |
| `FATCA_EXEMPT_REPORTING_CODE_H` | A regulated investment company as defined in section 851 or an entity registered at all times during the tax year under the Investment Company Act of 1940 |
| `FATCA_EXEMPT_REPORTING_CODE_I` | A common trust fund as defined in section 584(a) |
| `FATCA_EXEMPT_REPORTING_CODE_J` | A bank as defined in section 581 |
| `FATCA_EXEMPT_REPORTING_CODE_K` | A broker |
| `FATCA_EXEMPT_REPORTING_CODE_L` | A trust exempt from tax under section 664 or described in section 4947(a)(1) |
| `FATCA_EXEMPT_REPORTING_CODE_M` | A tax-exempt trust under a section 403(b) plan or section 457(g) plan |
| Code | Label | Description |
| :--------- | :------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------- |
| `EXEMPTBO` | Exempt beneficial owners | Entities generally exempt from FATCA, including foreign governments, central banks, and certain retirement funds or international organizations |
| `FFI` | Foreign Financial Institutions (FFIs) | Non-US entities that hold financial accounts or act as financial intermediaries, such as banks, investment funds, or custodians |
| `NFFE` | Non-Financial Foreign Entities (NFFEs) | Non-US entities that are not financial institutions, typically operating businesses engaged in trade, manufacturing, or services |
| `OTHER` | Other statuses | Accounts not considered financial accounts for FATCA purposes, which do not fall into the FFI, NFFE, or exempt categories |
| Code | Label |
| :--------------------------------------------------------------------- | :-------------------------------------------------------------------- |
| `CERTIFIED_DEEMED_COMPLIANT_INVESTMENT_ADVISERS_MANAGERS` | Certified deemed-compliant investment advisers/managers |
| `CERTIFIED_DEEMED_COMPLIANT_LIMITED_LIFE_DEBT_INVESTMENT_ENTITY` | Certified deemed-compliant limited-life debt investment entity |
| `CERTIFIED_DEEMED_COMPLIANT_LOCAL_BANK` | Certified deemed-compliant local bank |
| `CERTIFIED_DEEMED_COMPLIANT_LOW_VALUE_ACCOUNTS` | Certified deemed-compliant low-value accounts |
| `CERTIFIED_DEEMED_COMPLIANT_SPONSORED_CLOSELY_HELD_INVESTMENT_VEHICLE` | Certified deemed-compliant sponsored, closely held investment vehicle |
| `EXCEPTED_INTER_AFFILIATE` | Excepted inter-affiliate |
| `NONPARTICIPATING` | Nonparticipating |
| `NONREPORTING_IGA` | Nonreporting IGA |
| `OWNER_DOCUMENTED` | Owner-documented |
| `PARTICIPATING` | Participating |
| `REGISTERED_DEEMED_COMPLIANT_OTHER_THAN_MODEL_1` | Registered deemed-compliant (other than model 1) |
| `REPORTING_MODEL_1` | Reporting model 1 |
| `REPORTING_MODEL_2` | Reporting model 2 |
| `RESTRICTED_DISTRIBUTOR` | Restricted distributor |
| `SPONSORED_WITHOUT_GIIN` | Sponsored (without GIIN) |
| `TERRITORY_FINANCIAL_INSTITUTION` | Territory financial institution |
| Code | Label |
| :-------------------------------------------------------------- | :------------------------------------------------------------ |
| `501C_ORGANIZATION` | 501(c) organization |
| `ACTIVE` | Active |
| `DIRECT_REPORTING` | Direct reporting |
| `EXCEPTED_NONFINANCIAL_ENTITY_IN_LIQUIDATION_OR_BANKRUPTCY` | Excepted nonfinancial entity in liquidation or bankruptcy |
| `EXCEPTED_NONFINANCIAL_GROUP_ENTITY` | Excepted nonfinancial group entity |
| `EXCEPTED_NONFINANCIAL_STARTUP_COMPANY` | Excepted nonfinancial start-up company |
| `EXCEPTED_TERRITORY` | Excepted territory |
| `NONPROFIT_ORGANIZATION` | Nonprofit organization |
| `PASSIVE` | Passive |
| `PUBLICLY_TRADED_OR_AFFILIATE_OF_A_PUBLICLY_TRADED_CORPORATION` | Publicly traded or affiliate of a publicly traded corporation |
| `SPONSORED_DIRECT_REPORTING` | Sponsored direct reporting |
| Code | Label |
| :------------------------------------------------------- | :--------------------------------------------------------- |
| `ENTITY_WHOLLY_OWNED_BY_EXEMPT_BENEFICIAL_OWNERS` | Entity wholly owned by exempt beneficial owners |
| `EXEMPT_RETIREMENT_PLAN` | Exempt retirement plan |
| `FOREIGN_GOVERNMENT_US_POSSESSION_CENTRAL_BANK_OF_ISSUE` | Foreign government / US possession / central bank of issue |
| `INTERNATIONAL_ORGANIZATION` | International organization |
A unique `customerId` is returned, which is used in all future calls to identify this end client.
```json Request — US entity theme={null}
{
"applicationType": "RIA_PC_INSTITUTION",
"entries": [
{ "key": "legalEntityName", "value": "Encom LLC" },
{ "key": "hasDbaName", "value": true },
{ "key": "dbaNames", "value": "Encom Video Games" },
{ "key": "taxId", "value": "123456789" },
{ "key": "physicalCountry", "value": "US" },
{ "key": "physicalStreetAddress", "value": "123 Lightcycle Way" },
{ "key": "physicalCity", "value": "San Francisco" },
{ "key": "physicalStateUS", "value": "CA" },
{ "key": "physicalPostalCode", "value": "94104" },
{ "key": "hasProofOfAddress", "value": true },
{ "key": "taxClassificationUs", "value": "C_CORP" },
{ "key": "taxExemptionPayeeCode", "value": "TAX_EXEMPT_PAYEE_CODE_5" },
{ "key": "fatcaExemptionReportingCode", "value": "FATCA_EXEMPT_REPORTING_CODE_D" },
{ "key": "certifiedW9", "value": true }
]
}
```
```json Request — non-US entity theme={null}
{
"applicationType": "RIA_PC_INSTITUTION",
"entries": [
{ "key": "legalEntityName", "value": "Encom LLC" },
{ "key": "hasDbaName", "value": true },
{ "key": "dbaNames", "value": "Encom Video Games" },
{ "key": "businessRegistrationNumber", "value": "123456789" },
{ "key": "physicalCountry", "value": "GB" },
{ "key": "physicalStreetAddress", "value": "123 Lightcycle Way" },
{ "key": "physicalCity", "value": "London" },
{ "key": "physicalStateOther", "value": "London" },
{ "key": "physicalPostalCode", "value": "94104" },
{ "key": "hasProofOfAddress", "value": true },
{ "key": "taxClassificationNonUs", "value": "CORP" },
{ "key": "fatcaEntityType", "value": "NFFE" },
{ "key": "fatcaStatusNffe", "value": "PASSIVE" },
{ "key": "beneficialOwnersRequired", "value": true },
{
"key": "beneficiaryGroup",
"value": [
{
"beneficiaryFirstName": "John",
"beneficiaryLastName": "Smith",
"beneficiaryTaxId": "123456789",
"beneficiaryAllocation": "60",
"beneficiaryCountry": "GB",
"beneficiaryStreetAddress": "10 Downing Street",
"beneficiaryCity": "London",
"beneficiaryStateOther": "England",
"beneficiaryPostalCode": "SW1A 1AA"
},
{
"beneficiaryFirstName": "Jane",
"beneficiaryLastName": "Doe",
"beneficiaryTaxId": "987654321",
"beneficiaryAllocation": "40",
"beneficiaryCountry": "GB",
"beneficiaryStreetAddress": "221B Baker Street",
"beneficiaryCity": "London",
"beneficiaryStateOther": "England",
"beneficiaryPostalCode": "NW1 6XE"
}
]
},
{ "key": "certifiedW8", "value": true }
]
}
```
```json Response theme={null}
{
"data": {
"customerId": "d6f81b1563687f326ac9e3d4a00f9a0949e4ca81158cc47674846d27094b2503",
"status": "IN_PROGRESS"
}
}
```
### Step 2: Upload required documents
**`POST /v2/onboarding/customers/{{customerId}}/document`**
| **Tag** | **Description** | **Required** | **Type** | **Value restrictions** |
| :------------------- | :---------------------- | :------------------------------------ | :------- | :--------------------------------- |
| constitutionDocument | constitutional document | Yes | Upload | GIF, JPEG, PNG, or PDF — max 25 MB |
| proofOfAddress | proof of address | Yes, if `hasProofOfAddress` is `true` | Upload | GIF, JPEG, PNG, or PDF — max 25 MB |
Upload a single image file (GIF, JPEG, PNG, or PDF). If a second file is uploaded, the latest replaces the first. Multi-file archives are rejected. A signed upload URL is returned and accepts the document via a PUT request. The URL is valid for 15 minutes — if it expires, request a new one by calling this endpoint again.
```json Request theme={null}
{
"documentType": "constitutionDocument"
}
```
```json Response theme={null}
{
"data": {
"url": "https://storage.googleapis.com/anchorage/pii/v1/{{customerId}}/CONSTITUTION_DOCUMENT/{{documentId}}?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Expires=899&X-Goog-Signature={{signature}}"
}
}
```
Upload the image to the returned URL:
```bash theme={null}
curl -X PUT -H 'Content-Type: application/octet-stream' --data-binary @image.png {{step4url.response.body.data.url}}
```
### Step 3: Check onboarding status
**`GET /v2/onboarding/customers/{{customerId}}`**
Any errors or missing documents are listed in the `errors` section of the response.
```json Response theme={null}
{
"data": {
"customerId": "26c014539bd34e8e441e34381d9d5dad9434bb3645dbbf27d8267304e7ad0584",
"entries": [
{ "key": "legalEntityName", "value": "ACME Corp - 2025-04-11T11:08:11.771Z" },
{ "key": "dbaNames", "value": "Encom Video Games" },
{ "key": "taxId", "value": "123456789" },
{ "key": "hasProofOfAddress", "value": "Yes" },
{ "key": "physicalCity", "value": "San Francisco" },
{ "key": "physicalCountry", "value": "United States" },
{ "key": "physicalStateUS", "value": "California" },
{ "key": "physicalStreetAddress", "value": "123 Lightcycle Way" },
{ "key": "physicalPostalCode", "value": "94104" },
{ "key": "hasDbaName", "value": "Yes" }
],
"errors": [
{ "key": "constitutionDocument", "status": "MISSING", "value": "expected 1 answer for non-void triggered question, instead got 0" },
{ "key": "proofOfAddress", "status": "MISSING", "value": "expected 1 answer for non-void triggered question, instead got 0" }
],
"status": "IN_PROGRESS"
}
}
```
### Step 4: Submit the client application
**`POST /v2/onboarding/customers/{{customerId}}/submit`**
Once submitted, you can move on to opening the account — you don't need to wait for approval first (see the note above).
### Step 5: Check client approval status
**`GET /v2/onboarding/customers/{{customerId}}`**
Upon successful submission, status changes from `IN_PROGRESS` to `IN_REVIEW`. Once fully approved, status changes to `COMPLETE`. To receive asynchronous notification when approval completes, register for webhooks — see [Configure webhooks](/knowledge-base/platform/developers/webhooks/webhooks-configure).
### Step 6: Create the account
**`POST /v2/onboarding/subaccounts`**
Supported business account type:
| Account type | Subtype | End client(s) |
| :---------------------- | :------ | :------------ |
| `INSTITUTIONAL_TAXABLE` | — | 1 |
Expected program signers:
| Account type | Expected program signers |
| :---------------------- | :----------------------------------- |
| `INSTITUTIONAL_TAXABLE` | Initial set of named program signers |
Key fields:
| Field | Description | Required | Type | Restrictions |
| :------------------------------------------ | :----------------------------------------------- | :---------------------------------------- | :------ | :---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `legalEntityName` | Legal entity name | Yes | String | |
| `accountType` | Account type | Yes | Enum | `INSTITUTIONAL_TAXABLE` |
| `programSignerGroup` | List of program signers | Yes | Array | |
| `programSignerGroup/programSignerFirstName` | First name | Yes | String | |
| `programSignerGroup/programSignerLastName` | Last name | Yes | String | |
| `programSignerGroup/programSignerEmail` | Email | Yes | String | Valid email |
| `documentPreferenceAddressDefaultEmail` | Statement delivery email(s) | Yes | String | Comma-separated valid emails |
| `termsAgreementID` | Terms agreement ID | If T\&Cs enabled | String | ID from `/v2/onboarding/agreements/terms` — see [Terms and conditions](/knowledge-base/platform/developers/wealth/wealth-management-onboarding-terms-types) |
| `beneficiaryGroup` | Beneficiaries | No | Array | |
| `beneficiaryGroup/beneficiaryType` | Type | Yes | Enum | `SPOUSE`, `FAMILY_OR_FRIEND`, `CHARITY`, `TRUST`, `ESTATE` |
| `beneficiaryGroup/beneficiaryName` | Name | Yes | String | |
| `beneficiaryGroup/beneficiaryAllocation` | Allocation % | Yes, must sum to 100 | Number | 1–100 |
| `contingencyBeneficiaryGroup` | Contingency beneficiaries | No | Array | Same structure as `beneficiaryGroup` |
| `fees` | Fee configuration | No | Array | See [fee types](/knowledge-base/platform/developers/wealth/wealth-management-subaccounts#fee-types) |
| `isSegregated` | Wallet structure (omnibus or segregated wallets) | No, defaults to `false` (omnibus wallets) | Boolean | Org must opt into feature |
| `programCustomers` | Linked end clients | Yes | Array | |
| `programCustomers/programCustomerId` | End client ID | Yes | String | The `customerId` from Step 1 — or an existing client's `customerId` if you skipped onboarding |
| `programCustomers/programCustomerRole` | Role | Yes | Enum | `PRIMARY` or `SECONDARY` |
| `submit` | Submit immediately | No, defaults to `false` | Boolean | |
Each account requires a signer who can represent the client. The initial set of named program signers acts on the business's behalf.
```json Example request theme={null}
{
"name": "{{name}}",
"externalId": "{{externalId}}",
"submit": true,
"entries": [
{ "key": "legalEntityName", "value": "SubAccount INSTITUTIONAL_TAXABLE" },
{ "key": "accountType", "value": "INSTITUTIONAL_TAXABLE" },
{ "key": "isSegregated", "value": true },
{ "key": "documentPreferenceAddressDefaultEmail", "value": "kevin.flynn_4@test.com" },
{ "key": "programSignerGroup", "value": [
{ "programSignerFirstName": "Kevin", "programSignerLastName": "Flynn_5", "programSignerEmail": "kevin.flynn_5@test.com" },
{ "programSignerFirstName": "Kevin", "programSignerLastName": "Flynn_6", "programSignerEmail": "kevin.flynn_6@test.com" }
]
},
{ "key": "programCustomers", "value": [
{ "programCustomerId": "{{customerId1}}", "programCustomerRole": "PRIMARY" }
]
},
{ "key": "fees", "value": [
{ "feeType": "ADVISORY", "feeRate": "0.1" },
{ "feeType": "MANAGEMENT", "feeRate": "0.25", "feeIsBillable": true }
]
}
]
}
```
A unique `subaccountId` is returned for all future references to this account.
Add `termsAgreementId` to a program signer's entry only if [terms and conditions delivery](/knowledge-base/platform/developers/wealth/wealth-management-onboarding-terms-types) requires their explicit agreement. See [Onboarding examples](/knowledge-base/platform/developers/wealth/wealth-management-onboarding-examples) for complete request payloads, with and without a `termsAgreementId`, for every account type.
### Step 7: List account applications
**`GET /v2/onboarding/subaccounts`**
Returns all account onboarding applications associated with this API key. Supports `afterId` and `limit` for cursor pagination.
### Step 8: Check account status
**`GET /v2/onboarding/subaccounts/{subaccountId}`**
Errors and missing documents are listed in the `errors` array of the response.
### Step 9: Update the account application (if errors are present)
**`PUT /v2/onboarding/subaccounts/{subaccountId}`**
Uses the same `entries` array shape as Step 6. Only include the entries you want to change — omitted fields keep their existing value.
```json Example request theme={null}
{
"entries": [
{ "key": "documentPreferenceAddressDefaultEmail", "value": "kevin.flynn_4-updated@test.com" }
]
}
```
Any change to a client's data, or a request to terminate their account, is authenticated by Anchorage Digital Bank with the end client via DocuSign before processing.
### Step 10: Submit the account application (if `submit: false`)
**`POST /v2/onboarding/subaccounts/{subaccountId}/submit`**
### Step 11: Check account approval status
**`GET /v2/subaccounts/customers/accounts?subaccountIds={subaccountId}`**
Status values: `PENDING` (received, awaiting approval) → `OPEN` (approved and active). Alternatively, subscribe to the `subaccount.opened` webhook event for asynchronous notification.
***
## Reliance only: edit client information
RIAs with full or partial KYC reliance have access to a flow in which program customers are auto-approved. For these RIAs, select fields remain editable even after application status is `COMPLETE`.
| **Tag** | **Description** | **Required** | **Can edit** | **Type** | **Value restrictions** |
| :------------------------- | :------------------------------------------------------- | :-------------------------------------------------- | :----------- | :------- | :---------------------------------------------------------------------------------- |
| legalEntityName | legal entity name | Yes | No | String | |
| hasDbaName | does the organization have a registered DBA name? | Yes | Yes | Boolean | `true` or `false` |
| dbaNames | DBA name | Yes, if `hasDbaName` is `true` | Yes | String | |
| taxId | EIN | Yes (this or `businessRegistrationNumber` required) | No | Number | 9-digit number |
| businessRegistrationNumber | business registration number | Yes (this or `taxId` required) | No | String | |
| proofOfAddressContext | explanation when `hasProofOfAddress` is `false` | No | Yes | String | |
| legalStructure | legal structure of the business | No | No | Enum | `C_CORP`; `LLC`; `LLP`; `LP`; `S_CORP`; `SOLE_PROP`; `TRUST`; `NON_PROFIT`; `OTHER` |
| legalStructureOther | legal structure when `legalStructure` is `OTHER` | No | Yes | String | |
| physicalCountry | country | Yes | Yes | String | ISO 3166-1 alpha-2 country code |
| physicalStreetAddress | street address | Yes | Yes | String | |
| physicalCity | city name | Yes | Yes | String | |
| physicalStateUS | US state | Yes, for US country | Yes | String | 2-character USPS state code |
| physicalStateOther | non-US state or province | Yes, for non-US countries | Yes | String | |
| physicalPostalCode | zip code or postal code | Yes | Yes | String | |
| hasProofOfAddress | can you provide a proof of address? | Yes | Yes | Boolean | `true` or `false` |
| hasProofOfAddressContext | additional context if unable to provide proof of address | No | Yes | String | |
# Terms and conditions
Source: https://docs.anchorage.com/knowledge-base/platform/developers/wealth/wealth-management-onboarding-terms-types
Configure terms and conditions delivery method and KYC reliance model for end client onboarding.
How you deliver terms and conditions, and whether your integration uses a KYC reliance model, are configured once during setup — before you onboard your first client.
## Terms configuration
Two methodologies are supported for providing terms and conditions to program customers.
**Docusign** — Share an Anchorage Digital branded Docusign link for the customer to review and sign. Agreements are attached to a subaccount onboarding application.
**`POST /v2/onboarding/agreements/{agreementType}`** with `agreementType` set to `terms`.
| **Tag** | **Description** | **Required** | **Type** | **Value restrictions** |
| :------------------- | :--------------------------------------------------------- | :----------- | :------- | :-------------------------------------------------- |
| legalEntityName | legal entity name | Yes | String | |
| signerFirstName | signer's first name | Yes | String | |
| signerLastName | signer's last name | Yes | String | |
| signerEmail | signer's email address | Yes | String | valid e-mail address |
| termsAgreementFormat | agreement format | Yes | String | `docusign` (`anchorage` format has been deprecated) |
| returnUrl | URL to redirect to once terms and conditions are accepted | No | String | |
| frameAncestor | URL where the terms and conditions link should be embedded | No | String | |
A unique `termsAgreementId` is returned, which will be used in an end client onboarding application. A Docusign signed and timed `url` is also returned. A new signed URL is returned on each GET call as long as the terms are still `IN_PROGRESS`.
Anchorage Digital supports Docusign's Embedded Signing integration, which allows immediate signing within an app or website. Signed URLs are valid for **5 minutes** (a Docusign limit that cannot be changed) and should be generated immediately before use. If a URL expires, request a new one with a subsequent GET call to the agreement endpoint. All agreements must reflect a status of `COMPLETE` before submitting the full onboarding application. See [Docusign embedded signing documentation](https://developers.docusign.com/docs/esign-rest-api/esign101/concepts/embedding/embedded-signing/) for details.
**`GET /v2/onboarding/agreements/{agreementType}/{agreementId}`** with `agreementType` set to `terms` and `agreementId` set to the `termsAgreementId`.
Returns details of the agreement, including `status`. If still `IN_PROGRESS`, a new Docusign signed URL is returned.
**Hosted terms** — The preferred approach for partners, though it requires legal sign-off. Customers agree implicitly through onboarding, without a Docusign signature: provide the version of terms presented to the customer and the date they implicitly agreed. Contact your Anchorage Digital account representative to discuss enabling this flow.
## Reliance model configuration
This configuration supports partnerships that use full or partial reliance models. No reliance is the assumed default. Setting up an RIA for a reliance model requires explicit legal sign-off.
| Model | Behavior |
| :--------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Full reliance | Document uploads are not required and KYC checks are skipped, moving directly to approval. Anchorage Digital relies on the partner to perform KYC. |
| Partial reliance | Document uploads are not required at onboarding. KYB and individual profiles are submitted to Alloy; if Alloy returns approval, the application is auto-approved. |
| No reliance | The standard KYC process applies. |
# Overview
Source: https://docs.anchorage.com/knowledge-base/platform/developers/wealth/wealth-management-overview
Take the first step toward offering digital assets to your clients with Anchorage Digital's APIs.
Client demand for digital assets is no longer optional — wealth management clients want access to this asset class alongside their traditional holdings. Building institutional-grade custody, trading, and compliance infrastructure from scratch takes years and significant capital. Anchorage Digital gives you that infrastructure through a single integration, backed by an OCC-chartered, qualified custodian.
## Who this is for
**Wealth management firms, banks, and broker-dealers** build directly on Anchorage Digital's APIs to offer digital assets to their own clients, using the account structure and trading tools described in this guide.
**Turnkey asset management platforms** enable the advisory firms on their platform to offer digital assets to their clients, using the same underlying integration.
## What you can build
Onboard individual end clients and their subaccounts.
Onboard business end clients and their subaccounts.
Fund accounts with USD and process USD withdrawals.
Fund accounts with digital assets and process crypto withdrawals.
Trade and rebalance digital asset holdings across subaccounts.
Offer your clients loans backed by their digital assets.
Present statements to your clients.
Present tax documents and data to your clients.
Configure billing methods, fee rates, and manual billing charges.
Set up API permission groups, API keys, and the shared Anchorage Digital key.
Choose a terms delivery method and KYC reliance model for client onboarding.
# Statements
Source: https://docs.anchorage.com/knowledge-base/platform/developers/wealth/wealth-management-statements
Access statement types and reporting for wealth managers and end clients.
The wealth management platform provides statements and reports distinct from the standard custody offering, as it operates off the ledger.
## How it works
Anchorage Digital produces subaccount and program-level statements each month, covering starting and ending balances and all transactions during the period.
End clients and wealth managers each receive their statements by email, and can also view or download them from the web dashboard.
Use the Statements API to list, fetch, and download statements without relying on the web dashboard.
***
## Web dashboard access
All wealth manager and end-client statements are available on the web dashboard under the **Reporting** page. Click the PDF icon to download any statement.
***
## Statement components
Each statement includes:
1. **Starting and ending balance totals** — holdings at the start and end of the month.
2. **Transactions by subaccount** — all activity during the period.
***
## End-client monthly subaccount statements
In accordance with its custody obligations, Anchorage Digital Bank sends monthly statements directly to each end client at the email collected during due diligence. These cover all transactions and balances by subaccount.
***
## Wealth manager monthly statements
Wealth managers also receive statements via email. Statements are additionally available for download on the Anchorage Digital web dashboard.
***
## Wealth manager: Trade confirmations
Wealth managers receive trade confirmations from Anchorage Hold containing trading and brokerage fee details, including a breakdown of settlements across each subaccount. Wealth managers are responsible for disclosing trading fees to their end clients.
***
## Integration steps
Statements are also available programmatically, so you can pull and archive them without relying on the web dashboard.
### Step 1: List statement types
**`GET /v2/statement-types`**
```bash Request theme={null}
curl --request GET \
--url https://api.anchorage-staging.com/v2/statement-types \
--header 'Api-Access-Key: {API Key}' \
--header 'accept: application/json'
```
```json Response theme={null}
{
"data": [
{ "id": "b00e2483-57a1-4db4-8ea1-b91223a76a20", "name": "Brokerage Monthly Statement" },
{ "id": "d3b07384-d9a0-4f8b-8a1a-6f3e4b2e4f8b", "name": "Custody Monthly Statement" },
{ "id": "058da362-31a7-4e2b-ae3e-77b095389a5f", "name": "Exchange Trade Fund" },
{ "id": "e6ffd062-7bbc-4d72-b9d0-409f7fe7dd0d", "name": "Program Customer Monthly" },
{ "id": "cbe88de1-2470-46f1-aa59-932eeda16ba2", "name": "Registered Investment Advisor" }
],
"page": { "next": null }
}
```
### Step 2: List statements
**`GET /v2/statements`**
Filter by `typeIds`, `customerIds`, `ids`, or a `createdAfter`/`createdBefore` date range. Supports `afterId`/`limit` cursor pagination.
```bash Request theme={null}
curl --request GET \
--url 'https://api.anchorage-staging.com/v2/statements?customerIds={customerId}&createdAfter=2025-09-01' \
--header 'Api-Access-Key: {API Key}' \
--header 'accept: application/json'
```
```json Response theme={null}
{
"data": [
{
"id": "8de0fc33-7443-4dcf-bbf1-4ca8d0e0509f",
"customerId": "fbcdb420fca4439d919089e60d59cd5b12b692d215694681b636bffb6cb1618c",
"createdAt": "2025-03-27T17:15:42.793685Z",
"displayName": "ETF Statement October 2025",
"typeId": "058da362-31a7-4e2b-ae3e-77b095389a5f"
}
],
"page": { "next": null }
}
```
### Step 3: Get statement details
**`GET /v2/statements/{statementId}`**
```bash Request theme={null}
curl --request GET \
--url https://api.anchorage-staging.com/v2/statements/2cfb5ca8-8a71-11f0-969e-42010a1f04ea \
--header 'Api-Access-Key: {API Key}' \
--header 'accept: application/json'
```
```json Response theme={null}
{
"data": {
"id": "2cfb5ca8-8a71-11f0-969e-42010a1f04ea",
"customerId": "3ed6ef079913cb5e786c03f73326511b0bbebc438f941cb13650d48650904fc6",
"createdAt": "2025-09-01T00:47:16.937934Z",
"displayName": "RIA Statement September 2025",
"typeId": "058da362-31a7-4e2b-ae3e-77b095389a5f"
}
}
```
### Step 4: Download the statement PDF
**`GET /v2/statements/{statementId}/download`**
Returns the statement as a binary PDF (`application/pdf`), not a JSON envelope.
```bash Request theme={null}
curl --request GET \
--url https://api.anchorage-staging.com/v2/statements/2cfb5ca8-8a71-11f0-969e-42010a1f04ea/download \
--header 'Api-Access-Key: {API Key}' \
--header 'accept: application/pdf' \
--output statement.pdf
```
# Billing and fees
Source: https://docs.anchorage.com/knowledge-base/platform/developers/wealth/wealth-management-subaccounts
Configure billing methods and fee rates, and submit or cancel manual billing charges for end-client accounts.
Plan your billing and fee strategy before onboarding clients. Fees are configured per account and billed either automatically each cycle or manually through the API.
## How it works
Set the billing method (automated or manual) and fee rates when you create an account, or leave them to configure later.
Each fee accrues daily based on average assets under custody (AUC). The current accrual is visible on the account via `accruedFees`.
On the 1st of the month, the prior period's fees post to the ledger as a pending transaction.
After a dispute period, fees are finalized and withdrawn on the 10th business day.
You can also submit or cancel charges outside the automated cycle — see [Submit a manual billing charge](#step-1-submit-a-manual-billing-charge) below.
***
## Billing methods
| Method | Description |
| :---------------- | :------------------------------------------------------------------------------------------------ |
| Automated billing | Fees configured at account creation. Billed automatically each cycle. |
| Manual billing | Submitted by the wealth manager via the manual billing API endpoint before the 10th business day. |
## Fee model
| Model | Description |
| :-------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Bundled | Single "management fee" line item on the program customer's statement. Anchorage Digital's custody fee is deducted from the overall fee charged to the wealth manager. |
| Fully disclosed (unbundled) | Each fee type (custody, management, advisory, model) appears as a separate line item on the program customer's statement. |
## Fee types
| Fee type | Details |
| :--------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `CUSTODY_FEE` | Configured by Anchorage Digital during wealth manager onboarding. Rate may change based on total AUC per agreed commercial terms. Not configurable via API. Calculated from end-of-day USD value averaged over the fee period. |
| `MANAGEMENT_FEE` | Fee charged by the wealth manager for managing client assets (typically 1–2% of AUM with minimums). |
| `ADVISORY_FEE` | Configured via API at account creation. Used for third-party wealth manager fees; otherwise set to `0`. |
| `MODEL_FEE` | Configured via API at account creation. Used for model fees. |
## Fee visibility — `isBillable`
| Value | Behavior |
| :------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `isBillable: true` | Fee accrues daily AND is billed to the end-client account monthly. Shows as a separate line item on statements. Fees appear on the 1st of the month. Custody fee defaults to `true` for unbundled billing models. |
| `isBillable: false` | Fee accrues daily but is NOT billed to the account monthly. Does not appear on statements. Accrued balances are available via API. Useful for tracking internal fee distributions from a single management fee remittance. |
## Fee accruals
Each account includes an `accruedFees` section showing estimated fees based on average AUC — not actual point-in-time fees.
`accruedValue` represents the average fee accrued based on days elapsed and average AUC. It is **not** the actual fees charged based on prior day accruals, and should not be used to display mid-month "performance net of fees" estimates.
Key fields in `accruedFees`:
| Field | Description |
| :------------------ | :------------------------------------------------------------- |
| `startPeriod` | Billing month start date. |
| `endPeriod` | Billing month end date. |
| `accruedValue` | Accrued fee value to date for the billing period. |
| `rate` | Fee rate as a decimal (e.g., `0.01` = 1%). |
| `type` | Fee type corresponding to the `accruedFee` object. |
| `totalBalanceInUSD` | Most recent AUC balance in USD used to calculate accrued fees. |
| `state` | `ONGOING` — still accruing. `DONE` — billing period closed. |
```json Example account with fee accruals theme={null}
{
"createdAt": "2025-02-01T19:11:06.390Z",
"customerId": "9bcbbb3136356ff85670085f64cfb4f53419a94277261be0094c4d97de71a4yb",
"externalSubaccountId": "1A-13579-Doe",
"fees": [
{ "isBillable": true, "rate": 0, "startDate": "2024-08-02", "type": "ADVISORY" },
{ "isBillable": false, "rate": 0.0025, "startDate": "2024-11-20", "type": "CUSTODY" },
{ "isBillable": true, "rate": 0, "startDate": "2024-08-02", "type": "MANAGEMENT" },
{ "isBillable": true, "rate": 0, "startDate": "2024-08-02", "type": "MODEL" }
],
"name": "1A-13579-Doe",
"subaccountId": "99fc9d84-4843-4a2c-95cc-1d90385c7955",
"accruedFees": [
{
"accruedValue": "2982.05",
"endPeriod": "2025-01-31",
"rate": 0.351,
"startPeriod": "2025-01-01",
"state": "DONE",
"totalBalanceInUSD": "100032.1",
"type": "CUSTODY"
},
{
"accruedValue": "1731.5",
"endPeriod": "2025-02-18",
"rate": 0.351,
"startPeriod": "2025-02-01",
"state": "ONGOING",
"totalBalanceInUSD": "100031.22",
"type": "ADVISORY"
}
],
"balances": [
{ "assetType": "BTC", "availableForTrading": "0.00018915", "availableForWithdrawal": "0.00018915", "totalBalance": "0.00032102" },
{ "assetType": "ETH", "availableForTrading": "0.19400093", "availableForWithdrawal": "0", "totalBalance": "0" },
{ "assetType": "USD", "availableForTrading": "87676.46", "availableForWithdrawal": "87676.46", "totalBalance": "100000" }
]
}
```
`accruedValue` = (AvgAUC × feeRate) × (numberOfDays / 365)
Avg AUC is calculated from `totalBalance`. This is an estimate — do not use to calculate performance net of fees.
## Billing lifecycle
1. **Month 1, day 1** — Billing period starts. `accruedFee` begins calculating end of day. `state: ONGOING`.
2. **Month 1, days 2–30** — `accruedFee` reflects daily accrual from day 2.
3. **Month 1, last day** — Billing period closes. `state: DONE`.
4. **Month 2, day 1** — Fee transaction appears on the ledger at 8:00 AM ET as `PENDING`.
5. **Month 2, days 2–9th business day** — Billing dispute period. Contact your account point of contact with any questions.
6. **Month 2, 10th business day** — Billing finalized. Account transaction updates to `POSTED`. Fees withdrawn; wealth manager remittance begins. Updates at 8:00 AM ET.
Pro-rated fees apply to accounts with mid-month start dates.
## Additional billing considerations
1. **Manual billing** must be submitted via API before the 10th business day.
2. **Cash management** — Keep 3 months of USD in the account to avoid liquidation events that trigger taxable events.
3. **0-rate fees** — No accrual or transaction posted if rate is `0`.
4. **Negative USD balances** — If USD balance goes negative mid-month, it must be offset before the 10th business day.
5. **Rate changes** — Anchorage Digital emails end clients when fees with `isBillable: true` are created or changed.
6. **Fee rate format** — Configure as a decimal: `1% = 0.01`.
***
## Integration steps
Use manual billing when the wealth manager — not Anchorage Digital's AUC-based accrual — determines what to charge each end client. This applies to `ADVISORY`, `MODEL`, and `MANAGEMENT` fees only. Custody fees are set by Anchorage Digital and are never charged manually.
### Step 1: Submit a manual billing charge
**`POST /v2/subaccounts/billing/charges`**
| Field | Description | Required | Type |
| :--------------------- | :----------------------------------------- | :------- | :-------------------------------------- |
| `idempotentId` | Unique ID to prevent duplicate submissions | Yes | String |
| `feeType` | Fee type for this batch | Yes | Enum: `ADVISORY`, `MODEL`, `MANAGEMENT` |
| `interval` | Billing period this charge covers | Yes | Object with `startDate` and `endDate` |
| `charges` | Charges to create, up to 100 per request | Yes | Array |
| `charges/subaccountId` | Account to charge | Yes | String |
| `charges/amount` | Amount to charge, in USD | Yes | String |
Each request applies a single `feeType` and `interval` across all charges in the batch — submit separate requests to bill different fee types or periods in the same call.
```bash Request theme={null}
curl --request POST \
--url https://api.anchorage-staging.com/v2/subaccounts/billing/charges \
--header 'Api-Access-Key: {API Key}' \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--data '{
"idempotentId": "b6e1a9b2-5b64-4e6e-9b7a-6b6b6b6b6b6b",
"feeType": "MANAGEMENT",
"interval": {
"startDate": "2025-02-01",
"endDate": "2025-02-28"
},
"charges": [
{ "subaccountId": "cb80459c-a930-444e-8f17-69ba9d0e122f", "amount": "1000.00" }
]
}'
```
```json Response theme={null}
{
"data": {
"ids": ["9f4b2b3a-1c2d-4e5f-8a9b-0c1d2e3f4a5b"]
}
}
```
Manual charges debit the account immediately and appear on the statement dated the day the charge is submitted — they don't wait for the standard month-end billing cycle. A charge can only be canceled before it's finalized.
### Step 2: Cancel a charge (before it's finalized)
**`DELETE /v2/subaccounts/billing/charges/{chargeId}`**
Use the ID returned in Step 1.
```bash Request theme={null}
curl --request DELETE \
--url https://api.anchorage-staging.com/v2/subaccounts/billing/charges/9f4b2b3a-1c2d-4e5f-8a9b-0c1d2e3f4a5b \
--header 'Api-Access-Key: {API Key}' \
--header 'accept: application/json'
```
```json Response theme={null}
{
"data": {
"success": true
}
}
```
### Step 3: Update fee rates or billing dates
**`PATCH /v2/subaccounts/accounts/{subaccountId}`**
* Updates trigger email notifications to end clients and the wealth manager (including sandbox).
* Updated rates apply from the `startDate` specified.
* Mid-cycle updates retroactively apply to the current billing period.
* End-of-month billing uses the latest rate set for that month.
```bash Request theme={null}
curl --request PATCH \
--url https://api.anchorage-staging.com/v2/subaccounts/accounts/cb80459c-a930-444e-8f17-69ba9d0e122f \
--header 'Api-Access-Key: [API Key]' \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--data '{
"fees": [
{ "type": "ADVISORY", "rate": 0.01, "startDate": "2025-02-20" }
]
}'
```
```json Response theme={null}
{
"data": {
"subaccountId": "cb80459c-a930-444e-8f17-69ba9d0e122f"
}
}
```
# Tax
Source: https://docs.anchorage.com/knowledge-base/platform/developers/wealth/wealth-management-tax
Access and manage subaccount tax transactions, cost basis, inventory, gains/losses, and tax forms.
Tax data and forms for the wealth management integration cover cost basis, gains and losses, and IRS reporting for taxable and retirement accounts.
Anchorage Digital does not provide financial, tax, or legal advice.
## How it works
Anchorage Digital tracks cost basis, tax lots, and gains/losses for every subaccount as transactions occur.
Supply cost basis for in-kind deposits via API, and tag IRA-specific transaction types for accurate reporting.
Our tax reporting provider issues forms for taxable and retirement accounts based on the underlying tax data.
Use the tax API to pull transactions, inventory, gains, and signed form download links.
***
## Tax data overview
Anchorage Digital reports tax data for two account types:
1. **Taxable accounts** — individual, trust, joint, etc.
2. **Individual Retirement Accounts (IRA)**
### HIFO accounting method
Anchorage Digital uses **HIFO (highest-in, first-out)** by default — the highest-priced units are sold first when calculating cost basis. This can be changed at the wealth manager level or overridden per account.
**Example:** Investor holds 10 BTC at $20k, 20 BTC at $22k, 15 BTC at \$35k. Selling 25 BTC under HIFO:
* 15 BTC from the \$35k purchase sold first
* 10 BTC from the \$22k purchase sold next
### Tax reporting partnership
Anchorage Digital partners with a third-party tax reporting provider to give wealth managers and end clients required tax data, compliance features, and tax forms.
### Transaction types
| Type | Description |
| :---------------------- | :-------------------------------------------------------------------------------- |
| On-chain transactions | Asset movement on-chain. **Not relevant to tax APIs.** |
| Subaccount transactions | Asset movement on the wealth manager's ledger at Anchorage Digital. |
| Tax transactions | Any transaction with a taxable event — these are the transactions in the tax API. |
Taxable subaccount transaction event `types`: `DEPOSIT`, `TRADE`, `WITHDRAW`.
### Cost basis tracking
Cost basis is tracked automatically throughout the asset lifecycle. For **in-kind deposits**, the wealth manager and end client must supply the cost basis via API.
### `subaccountId` and `customerId` mapping
Each `subaccountId` maps 1:1 to an Account Owner ID with our tax reporting provider (which Anchorage Digital maps to `customerId`). This provides:
* **Accurate, segregated tracking** — clear traceability between strategies, trades, and their cost-basis impact.
* **Tax-loss harvesting flexibility** — losses can be realized within individual accounts without affecting others.
### Tax terminology
| Term | Description |
| :------------------- | :----------------------------------------------------------------------------------------------------------------- |
| Tax transaction | Data used by our tax reporting provider to generate tax outputs. Differs from subaccount or on-chain transactions. |
| Gain/loss | Difference between sale price and cost basis. Reported as `SHORT_TERM` or `LONG_TERM` by tax year. |
| Inventory | Total quantity and cost basis of a specific asset type held by a subaccount, comprised of multiple tax lots. |
| Tax lot | A group of units acquired at the same time and cost basis. |
| Acquisition date | Date an individual gains control of an asset. Determines long-term vs. short-term holding period in the US. |
| Cost basis | Value of an asset at acquisition time; used to calculate gain/loss on disposal. |
| Cost basis method | HIFO (default) or LIFO/FIFO (configurable). |
| Missing cost basis | Occurs when transferring assets in-kind into a deposit wallet. Can be supplied via API. |
| Holding period | Duration an asset is held. Long-term (>1 year) receives preferential US tax treatment. |
| Realized gain/loss | Gains/losses from actual sale or disposition of an asset. |
| Unrealized gain/loss | Gains/losses from price fluctuation without disposal. |
***
## Critical considerations
* **Missing cost basis is `null`**, not `0`.
* **Default method is HIFO** — configurable per wealth manager or per account.
* **All tax data is at the subaccount level**, regardless of account owners.
* **Trade rounding (dust):** Trades cannot always settle to full decimal precision. Rounded values are stored in the ledger and used for balancing, but full-precision quantities appear in trade confirmations and tax reporting — meaning tax data and ledger values may differ slightly by a small "dust" amount. This is an industry-wide issue with trade confirms vs. custody precision.
***
## Supported tax forms
Anchorage Digital does not perform tax reporting on behalf of wealth managers or end clients, and does not issue tax forms directly. Our tax reporting provider generates and provides forms based on the data Anchorage Digital provides.
| Account type | Form | Description | Deadline | Status |
| :----------- | :-------------- | :-------------------------------------------------------------------- | :------------------ | :-------- |
| Taxable | Cost-basis data | Proceeds and cost basis per transaction for Form 8949 and Schedule D. | Preferred by Feb 15 | |
| Taxable | 1099-B | Proceeds from brokerage/trading transactions. | Jan 31 | |
| Taxable | 1099-MISC | Miscellaneous income (staking rewards, services, mining). | Jan 31 | |
| Non-taxable | 1099-R | Distributions from retirement accounts. | Jan 31 | |
| Non-taxable | Form 5498 | IRA contribution reporting. | June 2 | |
***
## Integration steps
Sandbox tax testing may be limited due to the absence of a full trade → settlement lifecycle for mainnet assets.
### Step 1: Review tax transactions
**`GET /v2/tax/transactions/{subaccountId}`**
Returns tax transaction data for a subaccount. Check for missing cost basis on deposits.
```bash Request theme={null}
curl --request GET \
--url https://api.anchorage-staging.com/v2/tax/transactions/{subaccountId} \
--header 'Api-Access-Key: {API Key}' \
--header 'accept: application/json'
```
```json Response theme={null}
{
"data": [
{
"externalId": "dad566f7-d5e6-4bbf-a2ef-c092435163f9",
"fee": { "assetType": "ETH", "costBasis": "3335.22", "quantity": "0.029983029605243432217" },
"feeAsset": [{ "assetType": "ETH", "costBasis": "3335.22", "quantity": "0.029983029605243432217" }],
"id": "6159224d-db88-47a4-99ae-1e3b8aeed671",
"received": { "assetType": "ETH", "costBasis": "3335.22", "quantity": "29.983029605243432217" },
"receivedAsset": [{ "assetType": "ETH", "costBasis": "3335.22", "quantity": "29.983029605243432217" }],
"sent": { "assetType": "USD", "costBasis": "1", "quantity": "100000" },
"sentAsset": [{ "assetType": "USD", "costBasis": "1", "quantity": "100000" }],
"transactionTime": "2024-03-22T17:48:57.237Z",
"type": "TRADE"
}
]
}
```
### Step 2: Update missing cost basis
**`PATCH /v2/tax/transaction/{transactionId}`**
Only cost basis data can be updated. Transaction asset and quantity cannot be changed.
```bash Request theme={null}
curl --request PATCH \
--url https://api.anchorage-staging.com/v2/tax/transaction/{transactionId} \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--data '{
"type": "DEPOSIT",
"assetType": "BTC",
"lots": [
{
"acquisitionDatetime": "2025-03-03T14:48:06.111Z",
"quantity": "1.0",
"cost": "2500"
}
],
"acquisitionDatetime": "2025-03-03T14:48:06.111Z",
"data": {
"assetType": "BTC",
"costBasis": "2500",
"quantity": "1.0"
}
}'
```
```json Response theme={null}
{
"data": {
"transactionId": "9cd9f4d4-078b-4e44-a308-7662fec0f546"
}
}
```
### Step 3: View asset inventory
**`GET /v2/tax/inventory/{subaccountId}/{assetType}`**
Returns total quantity and all tax lots for a specific asset in a subaccount.
```bash Request theme={null}
curl --request GET \
--url https://api.anchorage-staging.com/v2/tax/inventory/{subaccountId}/LDO \
--header 'Api-Access-Key: {API Key}' \
--header 'accept: application/json'
```
```json Response theme={null}
{
"data": {
"summary": {
"AverageUnitCost": "1.633895117039317318810783072486812",
"assetType": "LDO",
"costBasis": "46.8803541265509",
"lots": [
{ "acquisitionDatetime": "2025-01-21T15:28:17.611Z", "cost": "5.0", "id": "164963b5-0bbd-505b-91c0-dbe8e309c900", "quantity": "2.646830567706262384", "unitCost": "1.889051781781781798" },
{ "acquisitionDatetime": "2025-01-21T15:20:31.747Z", "cost": "1.87858968297", "id": "ee406c6f-a955-50bc-92bb-aee73bcd7ae5", "quantity": "1", "unitCost": "1.87858968297" }
],
"quantity": "28.692388904068676642",
"totalQuantityMissingCostBasis": "0",
"totalQuantityWithCostBasis": "28.692388904068676642"
}
}
}
```
**`GET /v2/tax/inventory/summary/{subaccountId}`**
Returns inventory summary across all assets.
```bash Request theme={null}
curl --request GET \
--url https://api.anchorage-staging.com/v2/tax/inventory/summary/{subaccountId} \
--header 'Api-Access-Key: {API Key}' \
--header 'accept: application/json'
```
```json Response theme={null}
{
"data": [
{ "assetType": "SOL", "costBasis": "10.002517283800791293", "quantity": "0.048968461518597327", "quantityWithCostBasis": "0.048968461518597327", "quantityWithoutCostBasis": "0" },
{ "assetType": "ETH", "costBasis": "29.999999999999999002", "quantity": "0.012590000901477938", "quantityWithCostBasis": "0.010911660562946608", "quantityWithoutCostBasis": "0.00167834033853133" }
]
}
```
### Step 4: Review cost basis and gains
**`GET /v2/tax/gains/summary/{subaccountId}`**
Returns combined cost basis, proceeds, and gains/losses for a subaccount and time range.
```bash Request theme={null}
curl --request GET \
--url 'https://api.anchorage.com/v2/tax/gains/summary/{subaccountId}?startDateTime=2023-01-01T00:00:00Z&endDateTime=2025-03-01T23:59:59Z' \
--header 'Api-Access-Key: {API Key}' \
--header 'accept: application/json'
```
```json Response theme={null}
{
"data": {
"longTerm": { "assetType": "USD", "quantity": "0" },
"shortTerm": { "assetType": "USD", "quantity": "-87.133251361246620162189357418267650072" },
"total": { "assetType": "USD", "quantity": "-87.133251361246620162189357418267650072" }
}
}
```
**`GET /v2/tax/gains/costbasis/{subaccountId}`**
Returns per-disposal gain/loss records broken down into short-term and long-term, with cost basis and proceeds.
```bash Request theme={null}
curl --request GET \
--url 'https://api.anchorage.com/v2/tax/gains/costbasis/{subaccountId}?startDateTime=2023-01-01T00:00:00Z&endDateTime=2025-03-01T23:59:59Z' \
--header 'Api-Access-Key: {API Key}' \
--header 'accept: application/json'
```
```json Response theme={null}
{
"data": [
{
"acquisitionTxId": "995024a3-bcc1-5430-a2fd-7fc448cd2dd1",
"cost": { "assetType": "USD", "quantity": "40.012" },
"costBasisDate": "2024-12-04T20:25:59.509Z",
"dispositionTxId": "61ab9b9f-f2e3-5342-aa8f-1d56386379d6",
"gain": { "assetType": "USD", "quantity": "-0.0419952" },
"gainType": "short-term",
"proceeds": { "assetType": "USD", "quantity": "39.9700048" },
"saleDate": "2024-12-04T20:38:37.544Z",
"sold": { "assetType": "USDC", "quantity": "40" },
"taxYear": "2024"
}
]
}
```
### Step 5: Fetch tax forms
**`GET /v2/tax/subaccounts/{subaccountId}/forms`**
Returns pre-signed download links for a subaccount's tax forms. Links are time-limited.
```bash Request theme={null}
curl --request GET \
--url https://api.anchorage-staging.com/v2/tax/subaccounts/{subaccountId}/forms \
--header 'Api-Access-Key: {API Key}' \
--header 'accept: application/json'
```
```json Response theme={null}
{
"data": [
{
"forms": [
{
"downloadLink": "",
"formType": "1099_B"
}
],
"subaccountId": "32ee4b77-7f2a-4486-86f8-01c6bc8e4fda"
}
]
}
```
**`GET /v2/tax/clients/{customerId}/forms`**
Returns forms for all subaccounts belonging to a `customerId`. Use `customerId` as `affiliateId`.
```bash Request theme={null}
curl --request GET \
--url https://api.anchorage-staging.com/v2/tax/clients/{customerId}/forms \
--header 'Api-Access-Key: {API Key}' \
--header 'accept: application/json'
```
```json Response theme={null}
{
"data": [
{
"forms": [],
"subaccountId": "bb41b0c4-b3d7-4132-94d0-9ae2293bca5e"
},
{
"forms": [
{
"downloadLink": "",
"formType": "1099_B"
}
],
"subaccountId": "32ee4b77-7f2a-4486-86f8-01c6bc8e4fda"
}
]
}
```
### Step 6: Tag or untag a transaction
IRA transactions need a tag identifying the retirement-specific event type before they can be reflected correctly on 1099-R and Form 5498 reporting.
**`POST /v2/tax/transaction/{transactionId}/tag`**
`tag` values:
| Value | Description |
| :------------------- | :---------------------------------------------------------- |
| `contribution` | Contribution to a retirement account. |
| `transfer-in` | Assets transferred into the account. |
| `conversion` | Conversion (e.g., Traditional IRA to Roth IRA). |
| `distribution` | Distribution from the account. Requires `distributionCode`. |
| `transfer-out` | Assets transferred out of the account. |
| `recharacterization` | Recharacterized contribution. |
| `late-rollover` | Late rollover. Requires `postponedLateReason`. |
| `postponed` | Postponed contribution. Requires `postponedLateReason`. |
| `rollover` | Rollover contribution. |
`distributionCode` is required when `tag` is `distribution`, and must be a valid IRS Form 1099-R distribution code (for example, `7` for a normal distribution or `4` for death). `postponedLateReason` is required when `tag` is `postponed` or `late-rollover`.
```bash Request theme={null}
curl --request POST \
--url https://api.anchorage-staging.com/v2/tax/transaction/{transactionId}/tag \
--header 'Api-Access-Key: {API Key}' \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--data '{
"accountId": "cb80459c-a930-444e-8f17-69ba9d0e122f",
"tag": "distribution",
"distributionCode": "7",
"taxYear": "2025"
}'
```
```json Response theme={null}
{
"data": {
"status": "accepted"
}
}
```
To remove a tag, use **`DELETE /v2/tax/transaction/{transactionId}/tag`**:
```bash Request theme={null}
curl --request DELETE \
--url https://api.anchorage-staging.com/v2/tax/transaction/{transactionId}/tag \
--header 'Api-Access-Key: {API Key}' \
--header 'accept: application/json'
```
```json Response theme={null}
{
"data": {
"status": "accepted"
}
}
```
# Tax optimization
Source: https://docs.anchorage.com/knowledge-base/platform/developers/wealth/wealth-management-tax-optimization
Identify and execute crypto tax-loss harvesting opportunities for wealth management client accounts.
Advisors use the **Tax Optimization** page to find tax-loss harvesting opportunities across client accounts on Anchorage Digital Wealth. Review unrealized losses at the account or lot level, select the positions to sell, and execute the trade as a straight sale or a sell-and-buy-back that preserves market exposure.
Anchorage Digital does not provide financial, tax, or legal advice.
## How it works
Start from a client's account summary or the full **Tax Optimization** page to see unrealized losses and gains across eligible accounts.
Choose specific tax lots, or select by asset and configure how much of each position to sell.
Sell the selection outright, or sell and buy back to realize the loss while maintaining market exposure.
Track the resulting order and trade ticket through settlement, and see the realized loss or gain reflected for tax reporting.
***
## Eligible accounts
Only accounts where a realized loss has tax value are eligible for harvesting. Tax-advantaged retirement accounts are excluded, since losses inside them can't be realized for tax purposes.
| Account type | Eligible |
| :------------------------------- | :-------: |
| Individual | |
| Joint (JTWROS) | |
| C-Corp | |
| LLC | |
| LLP | |
| LP | |
| S-Corp | |
| Sole Proprietorship | |
| Non-Profit | |
| Trust | |
| Traditional IRA | |
| Roth IRA | |
| Rollover IRA | |
| Rollover Roth IRA | |
| Beneficiary Traditional/Roth IRA | |
| Roth Conversion | |
Within an eligible account, only assets with a recorded cost basis can be harvested. See [Update missing cost basis](#update-missing-cost-basis) for positions that need one.
***
## Reviewing opportunities
At the client and account level, a **Tax Optimization** summary card shows how many of the client's accounts are eligible, along with four figures: **Total Unrealized Losses**, **Total Unrealized Gains**, **Realized Net Gain/Loss**, and **Net Harvestable Loss**. Each figure is also broken out by **Short Term** and **Long Term** holding period, showing unrealized losses and gains alongside realized figures — net gain/loss, gains year-to-date, and losses year-to-date. Select **Harvest Opportunities** from this card to open the full **Tax Optimization** page.
The **Tax Optimization** page opens with the same summary figures, scoped to the accounts assigned to the advisor rather than a single client. The same rolled-up view is also available at the firm or rep code level.
### Opportunities table
Below the summary, the **Opportunities** table lists harvestable positions across **Losses** and **Gains** tabs. Within either tab, switch between two views:
* **By Asset** — aggregates all lots for a given asset. Selling from this view uses [HIFO](/knowledge-base/platform/developers/wealth/wealth-management-tax#hifo-accounting-method) (highest cost basis sold first).
* **By Lot** — shows each individual tax lot separately, with its own quantity and cost basis. Selling from this view uses Spec ID (specific identification), so the exact lots you select are the lots reported as sold.
The **By Asset** view includes the following columns:
| Column | Description |
| :--------------------- | :------------------------------------------------------------------ |
| Client | The client the holding belongs to |
| Asset | The digital asset held |
| Date Acquired | Date range covering when the underlying lots were acquired |
| Total Qty | Total quantity held of the asset |
| Qty with Cost Basis | Quantity for which cost basis is known |
| Qty with No Cost Basis | Quantity for which cost basis is missing, for example from deposits |
| Cost Basis | Total cost basis across lots with known basis |
| Market Value | Current market value of the holding |
The **By Lot** view shows the same holdings broken into individual lots, each with its own quantity and cost basis, instead of the aggregated split.
### Filters
Narrow the **Opportunities** table by client, asset, account, rep code, term (short-term or long-term), threshold (a minimum percentage or dollar amount of unrealized gain or loss), model settings, or firm.
***
## Update missing cost basis
Positions that arrived as deposits, rather than being bought through Anchorage Digital Wealth, may not have a recorded cost basis. These appear in the **Opportunities** table as **Qty with No Cost Basis** and can't be harvested until a cost basis is added.
Go to the **Transactions & Orders** page, select the **All Transactions** tab, then find the deposit that's missing cost basis.
In the **Actions** column, select the pencil icon.
Enter the quantity and cost basis for each lot that makes up the asset position, then save.
Once saved, the position's cost basis updates on the **Tax Optimization** page and becomes eligible to include in a harvest.
***
## Selecting and configuring a harvest
* **By Lot** — select the individual lots you want to harvest directly from the table.
* **By Asset** — select the asset-level opportunities you want to harvest, then configure how much of each position to sell: **Max**, a percentage, a dollar amount, or an asset quantity. Only assets with cost basis can be harvested. A bulk configuration option applies the same harvest amount across multiple selected assets at once.
As you configure positions, the view shows, per client and position, the total quantity, market value, cost basis, harvest amount, and resulting loss to realize — along with running totals for **Total Market Value to Harvest** and **Total Loss to Realize**, and how the client's Realized Net Gain/Loss, including its short-term and long-term split, will change once the harvest executes.
***
## Trade workflow
After configuring the harvest, choose one of two trade options:
1. **Sell-only** — sell the selection and hold proceeds as USD.
2. **Sell-and-buy-back** — sell the selection, then use the proceeds to reestablish exposure, either back into the same asset or into the model it was originally part of.
Before execution, you see a trade preview screen with the same treatment as the standard trading experience.
Once executed, the trade routes through standard trading operations:
* An open order is created and displayed with a standard order status.
* A sell-only trade generates a single trade ticket; a sell-and-buy-back generates two — one for the sell, one for the buy-back.
* The realized loss or gain is recorded for tax reporting.
Order and trade status can be monitored the same way as any standard trade, through to settlement. See [Trading](/knowledge-base/platform/developers/wealth/wealth-management-trading) for order and settlement status values.
***
## Harvesting step by step
### Harvesting by asset
Go to the **Tax Optimization** page from a client's account, or from the firm or rep code level.
Select the **Losses** or **Gains** tab depending on your goal, then switch to the **By Asset** view. Optionally apply filters to narrow the list.
Select the asset(s) you want to harvest.
For each position, choose **Max**, a percentage, a dollar amount, or an asset quantity. Use bulk configuration to apply the same amount across multiple selected assets.
Check the total quantity, market value, cost basis, harvest amount, and loss to realize, along with the running totals for Total Market Value to Harvest and Total Loss to Realize.
Select **Sell-only** or **Sell-and-buy-back**, review the trade preview screen, then confirm and submit the trade.
Track the resulting order and trade ticket(s) as you would any standard trade.
### Harvesting by lot
Go to the **Tax Optimization** page from a client's account, or from the firm or rep code level.
Select the **Losses** or **Gains** tab depending on your goal, then switch to the **By Lot** view. Optionally apply filters to narrow the list.
Select the specific lot(s) you want to harvest.
Check the total quantity, market value, cost basis, harvest amount, and loss to realize, along with the running totals for Total Market Value to Harvest and Total Loss to Realize.
Select **Sell-only** or **Sell-and-buy-back**, review the trade preview screen, then confirm and submit the trade.
Track the resulting order and trade ticket(s) as you would any standard trade.
# Trading
Source: https://docs.anchorage.com/knowledge-base/platform/developers/wealth/wealth-management-trading
Submit single and block trade orders, manage pricing data, and understand the settlement lifecycle.
Let your clients trade their custodied assets. Submit a single order for one account, or a block order allocated across many accounts at the same execution price — Anchorage Digital handles settlement automatically.
## How it works
Confirm the account has enough `availableForTrading` balance for the trade.
Pull real-time pricing from the WebSocket market data stream before submitting an order.
Submit a single or block order over REST or WebSocket.
Track order and trade status as the trade fills. Anchorage Digital settles automatically and updates account balances — no action required from you.
Testing in sandbox differs from production. Settlement testing is limited due to a mismatch between tradeable and testnet assets.
***
## Asset support
Asset support for the wealth management integration is a subset of Anchorage Digital's full custody asset list. Fetch supported assets from **`GET /v2/trading/pairs`**.
### Trading locations
As of July 2026:
| Trading location | Trading Entity |
| :--------------- | :------------------------ |
| US (Non-NY) | Anchorage Hold, LLC |
| NY | Anchorage Digital NY, LLC |
### Supported assets
As of July 2026, wealth manager clients have access to the following curated selection of digital assets supported by Anchorage Digital for custody and trading.
| Asset Name | Asset Symbol | Asset Type | Trading Entity |
| :---------------------- | :------------- | :--------- | :------------------------------------------------ |
| Aave | AAVE | ERC-20 | Anchorage Hold, LLC and Anchorage Digital NY, LLC |
| Cardano on Cardano | ADA\_CARDANO | Native | Anchorage Hold, LLC and Anchorage Digital NY, LLC |
| ApeCoin | APE | ERC-20 | Anchorage Hold, LLC and Anchorage Digital NY, LLC |
| Aptos | APT | Native | Anchorage Hold, LLC and Anchorage Digital NY, LLC |
| Cosmos | ATOM | Native | Anchorage Hold, LLC and Anchorage Digital NY, LLC |
| Avalanche (Native) | AVAX | Native | Anchorage Hold, LLC and Anchorage Digital NY, LLC |
| Axie Infinity | AXS | ERC-20 | Anchorage Hold, LLC and Anchorage Digital NY, LLC |
| Balancer | BAL | ERC-20 | Anchorage Hold, LLC and Anchorage Digital NY, LLC |
| Basic Attention Token | BAT | ERC-20 | Anchorage Hold, LLC and Anchorage Digital NY, LLC |
| Bitcoin Cash | BCH | Native | Anchorage Hold, LLC and Anchorage Digital NY, LLC |
| Binance Coin | BNB\_BSC | Native | Anchorage Hold, LLC |
| Bitcoin | BTC | Native | Anchorage Hold, LLC and Anchorage Digital NY, LLC |
| Compound Token | COMP | ERC-20 | Anchorage Hold, LLC and Anchorage Digital NY, LLC |
| Cronos | CRO | ERC-20 | Anchorage Hold, LLC and Anchorage Digital NY, LLC |
| Curve DAO | CRV | ERC-20 | Anchorage Hold, LLC and Anchorage Digital NY, LLC |
| Maker Dai | DAI | ERC-20 | Anchorage Hold, LLC and Anchorage Digital NY, LLC |
| Dogecoin | DOGE | Native | Anchorage Hold, LLC and Anchorage Digital NY, LLC |
| Polkadot on Polkadot | DOT\_POLKADOT | Native | Anchorage Hold, LLC and Anchorage Digital NY, LLC |
| Ethereum | ETH | Native | Anchorage Hold, LLC and Anchorage Digital NY, LLC |
| Filecoin | FIL | Native | Anchorage Hold, LLC and Anchorage Digital NY, LLC |
| The Graph | GRT | ERC-20 | Anchorage Hold, LLC and Anchorage Digital NY, LLC |
| Hedera | HBAR\_HBAR | Native | Anchorage Hold, LLC and Anchorage Digital NY, LLC |
| HYPE on HyperEVM | HYPE\_HYPEREVM | Native | Anchorage Hold, LLC and Anchorage Digital NY, LLC |
| Immutable X | IMX | ERC-20 | Anchorage Hold, LLC and Anchorage Digital NY, LLC |
| Lido Protocol | LDO | ERC-20 | Anchorage Hold, LLC and Anchorage Digital NY, LLC |
| Chainlink | LINK | ERC-20 | Anchorage Hold, LLC and Anchorage Digital NY, LLC |
| Litecoin | LTC | Native | Anchorage Hold, LLC and Anchorage Digital NY, LLC |
| Decentraland | MANA | ERC-20 | Anchorage Hold, LLC and Anchorage Digital NY, LLC |
| Near | NEAR\_NEAR | Native | Anchorage Hold, LLC and Anchorage Digital NY, LLC |
| Polygon Ecosystem Token | POL | ERC-20 | Anchorage Hold, LLC and Anchorage Digital NY, LLC |
| Quant | QNT | ERC-20 | Anchorage Hold, LLC and Anchorage Digital NY, LLC |
| The Sandbox | SAND | ERC-20 | Anchorage Hold, LLC and Anchorage Digital NY, LLC |
| Shiba Inu | SHIB | ERC-20 | Anchorage Hold, LLC and Anchorage Digital NY, LLC |
| Synthetix | SNX | ERC-20 | Anchorage Hold, LLC and Anchorage Digital NY, LLC |
| Solana | SOL | Native | Anchorage Hold, LLC and Anchorage Digital NY, LLC |
| StarkNet Token | STRK | ERC-20 | Anchorage Hold, LLC and Anchorage Digital NY, LLC |
| Sui | SUI | Native | Anchorage Hold, LLC and Anchorage Digital NY, LLC |
| Sushiswap | SUSHI | ERC-20 | Anchorage Hold, LLC and Anchorage Digital NY, LLC |
| TRX on TRON | TRX\_TRON | Native | Anchorage Hold, LLC |
| Uniswap | UNI | ERC-20 | Anchorage Hold, LLC and Anchorage Digital NY, LLC |
| USD Coin | USDC | ERC-20 | Anchorage Hold, LLC and Anchorage Digital NY, LLC |
| Tether | USDT | ERC-20 | Anchorage Hold, LLC |
| Wrapped Bitcoin | WBTC | ERC-20 | Anchorage Hold, LLC and Anchorage Digital NY, LLC |
| Worldcoin | WLD | ERC-20 | Anchorage Hold, LLC and Anchorage Digital NY, LLC |
| XDC Network on XDC | XDC\_XDC | Native | Anchorage Hold, LLC and Anchorage Digital NY, LLC |
| Stellar | XLM | Native | Anchorage Hold, LLC and Anchorage Digital NY, LLC |
| Ripple | XRP | Native | Anchorage Hold, LLC and Anchorage Digital NY, LLC |
| yearn.finance | YFI | ERC-20 | Anchorage Hold, LLC and Anchorage Digital NY, LLC |
| 0x (Zero X) | ZRX | ERC-20 | Anchorage Hold, LLC and Anchorage Digital NY, LLC |
### Trade precision and minimums
Minimum order sizes and precision increments are returned by **`GET /v2/trading/pairs`** and enforced at order submission. You can also call the RFQ endpoint beforehand to verify quote precision and minimum trade size (requires `tradingAccountId`).
```json Example asset data theme={null}
{
"data": [
{
"description": "Buy AAVE with USD, or Sell AAVE for USD",
"pair": "AAVE-USD",
"referenceData": {
"baseAssetType": "AAVE",
"baseSizeIncrement": "0.00000001",
"lastUpdateTime": "2024-07-09T15:57:55.249Z",
"minimumOrderSize": "0.000000010000000000000002",
"priceIncrement": "0.0000001",
"quoteAssetType": "USD",
"quoteSizeIncrement": "0.01"
}
}
]
}
```
| Field | Description |
| :------------------- | :------------------------------------------------------------------------------------------------------- |
| `baseSizeIncrement` | Minimum size increment when specifying order quantity in the base asset. Maximum decimal places allowed. |
| `quoteSizeIncrement` | Minimum size increment in the quote asset (e.g., USD to 2 decimal places = `0.01`). |
| `priceIncrement` | Minimum price increment in the response from the liquidity provider. |
| `minimumOrderSize` | Minimum required base asset size to place an order. |
***
## Order types
Supported order type: **Limit FoK**.
**Single orders** are ideal for tailored portfolio management or direct client trade requests. Also used to on/off-ramp specific assets without rebalancing across accounts.
**Block trades** execute multiple account allocations as a single institutional order — same execution price for all underlying trades. Routes to liquidity providers via smart order routing.
Block trade requirements:
* All allocations must sum to the total order quantity.
* All allocations must meet `availableForTrading` balance — if any allocation fails, the entire order fails.
* Allocations are capped at 1,000 per order.
* Allocation quantity must match the order's currency.
* All orders are Fill-or-Kill (FoK).
* Programmatic cancellations and short selling are not supported.
***
## Settlement lifecycle
Settlement is fully automated by Anchorage Digital.
Unsettled balances are available for trading immediately but not for withdrawal until settled. Anchorage Digital funds network fees for settlement activity — these are tracked in the "FBO gas fees" account and funded regularly by Anchorage Digital, with no action required from the wealth manager.
**Settlement status values**
| Status | Description |
| :------------------------------------------------------- | :-------------------------------------------------------------------------------------------------- |
| `PENDING` | Settlement created; covers one or more trades. |
| `SETTLING` | Funds transferred from wealth manager wallets; Anchorage Digital settling with liquidity providers. |
| `SETTLED` | All funds settled; account balances updated. |
| `CANCELED` | Settlement canceled. |
| `EXECUTED`, `REJECTED`, `PENDINGALLOCATION`, `ALLOCATED` | Internal statuses — not applicable to the wealth management use case. |
**Settlement types:** `TRADE` | `FEE` (custody, advisory, model, management)
**Automated settlement status flow**
| Event | Trade status | Settlement status |
| :------------------------ | :----------- | :---------------- |
| Trade executed | `EXECUTED` | — |
| Trade added to settlement | `EXECUTED` | `PENDING` |
| First leg settled | `SETTLING` | `SETTLING` |
| Second leg settled | `SETTLED` | `SETTLED` |
***
## Integration steps
### Step 1: Check available balance to trade
**`GET /v2/subaccounts/customers/{customerId}/accounts`**
Fetch `availableForTrading` per account. This balance includes unsettled assets, which are also tradeable.
```json Response theme={null}
"balances": [
{
"assetType": "BTC",
"totalBalance": "1",
"availableForWithdrawal": "0.5",
"availableForTrading": "0.5"
}
]
```
### Step 2: Subscribe to pricing data
Pull real-time asset price data from the WebSocket market data stream: configure the WebSocket connection, subscribe to the asset's USD price feed, then use the response data when submitting orders.
```python Subscribe to market data theme={null}
def subscribe_marketdata(ws, symbol, receiver):
msg = json.dumps({
"messageType": "MarketDataSnapshotRequest",
"timestamp": datetime.now().isoformat(),
"payload": {
"type": "subscribe",
"symbol": symbol,
"reqId": str(uuid.uuid4())
}
})
ws.send(msg)
while True:
resp = json.loads(ws.recv())
receiver(resp)
```
```json Market data snapshot response theme={null}
{
"messageType": "MarketDataSnapshot",
"timestamp": "2023-02-08T14:19:44Z",
"payload": {
"asks": [
{ "price": "23083.25076763", "size": "1" },
{ "price": "23084.28705625", "size": "4" }
],
"bids": [
{ "price": "23081.96", "size": "1" },
{ "price": "23080.96918517", "size": "4" }
],
"reqId": "e07b9683-af27-481a-b4db-1c492114e930",
"symbol": "BTC-USD"
}
}
```
### Step 3: Submit an order
Submission methods: REST API (**`POST /v2/trading/order`**) or [WebSocket](/knowledge-base/platform/developers/trading/websocket-getting-started).
Key submission rules:
1. Include a 1–5% buffer on `limitPrice` to reduce rejections during price volatility. Execution still fills at best market rate.
2. Submit in USD for buys; submit in-kind for sells.
3. `accountId` is not required for account-level trades.
4. `baseSizeIncrement` — round allocation quantities to this precision before submission. The parent order uses this precision when routing to liquidity providers.
```bash REST Request theme={null}
curl --request POST \
--url https://api.anchorage-staging.com/v2/trading/order \
--header 'Api-Access-Key: [API Key]' \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--data '{
"clOrderId": "6fb5fc79-0bb4-446d-82dd-d4687fb56a02",
"symbol": "BTC-USD",
"side": "BUY",
"currency": "USD",
"quantity": "100.00",
"orderType": "LIMIT",
"limitPrice": "100004.05",
"timestamp": "2025-02-20T18:32:51.133Z",
"allocation": [
{ "subaccountId": "ec761b5e-fd2c-497a-a9a0-f8738ac97bd", "quantity": "10" },
{ "subaccountId": "bc1234e-12v3-ab31-1234-gf8738ac597bd", "quantity": "90" }
]
}'
```
```json REST Response (filled) theme={null}
{
"data": {
"clOrderId": "6fb5fc79-0bb4-446d-82dd-d4687fb56a02",
"orderId": "a94c8d75-6c9d-4903-95f3-5b0893e76cb7",
"symbol": "BTC-USD",
"side": "BUY",
"currency": "USD",
"orderType": "MARKET",
"orderStatus": "FILLED",
"avgPx": "21005.4",
"orderQty": "10000.00",
"cumQty": "10000.00",
"counterQty": "0.4760680586896702",
"fee": "0.00001359805",
"feeCurrency": "BTC",
"transactTime": "2022-11-20T20:32:16.423Z"
}
}
```
```json WebSocket Submit order theme={null}
{
"messageType": "NewOrderSingle",
"timestamp": "2023-03-12T22:22:09.925952Z",
"payload": {
"clOrderId": "47ce2580-5e57-45d8-b67f-71a5aa55d05f",
"symbol": "BTC-USD",
"side": "SELL",
"currency": "USD",
"quantity": "10000",
"orderType": "LIMIT",
"limitPrice": "21000",
"timeInForce": "GTC",
"accountId": "3fa8372d-b51d-44ab-a456-43e947e4be10"
}
}
```
```json WebSocket Execution report (filled) theme={null}
{
"messageType": "ExecutionReport",
"payload": {
"clOrderId": "47ce2580-5e57-45d8-b67f-71a5aa55d05f",
"symbol": "BTC-USD",
"orderStatus": "FILLED",
"avgPx": "21990.01",
"cumQty": "10000",
"fee": "0.00045521",
"feeCurrency": "BTC",
"transactTime": "2023-03-12T22:22:09.925050Z"
}
}
```
```json WebSocket Execution report (rejected) theme={null}
{
"messageType": "ExecutionReport",
"payload": {
"clOrderId": "47ce2580-5e57-45d8-b67f-71a5aa55d05f",
"symbol": "BTC-USD",
"orderStatus": "REJECTED",
"rejectReason": "Invalid request",
"rejectReasonText": "invalid price: 21500.0001, must be multiplication of 0.01",
"transactTime": "2023-03-12T22:22:09.925050Z"
}
}
```
Implement retry logic for REST order submissions:
* Retry after 1s, 2s, then 4s on non-201 errors.
* A 201 response with `REJECTED` status indicates a liquidity provider issue (insufficient liquidity, min order size) — retries will not help.
* A 500 error typically indicates an account balance issue.
### Step 4: Monitor order and trade status
**Order status values**
| Status | Description |
| :--------- | :-------------------------------------------------------------------------------------- |
| `FILLED` | Order fully executed. |
| `CANCELED` | Limit FoK order did not cross the book. Safe to resubmit. |
| `REJECTED` | Poorly formatted, liquidity provider issue, or internal error. Do not retry repeatedly. |
**Trade status values**
| Status | Description |
| :--------- | :------------------------------------------------------------------------------------------------- |
| `PENDING` | Trade accepted; temporary status while Anchorage Digital receives fill details from market makers. |
| `EXECUTED` | Fill price and fees available; pre-settlement. |
| `SETTLING` | Netted balances sent to Anchorage Digital; settling with liquidity providers. |
| `SETTLED` | All funds settled; account balances updated. |
| `REJECTED` | Trade failed — asset volatility exceeded slippage or insufficient trading limit. |
| `CANCELED` | Trade canceled manually. |
***
## Full example
Checking balances, submitting a block order, and monitoring its status end to end:
```python theme={null}
import requests
import uuid
request_headers = {
"accept": "application/json",
"content-type": "application/json",
"Api-Access-Key": "[API Key]"
}
customer_id = "[customerId]"
# Step 1: Get account balances
response = requests.get(
f"https://api.anchorage-staging.com/v2/subaccounts/customers/{customer_id}/accounts",
headers=request_headers
)
data = response.json()["data"]
# check availableForTrading per account
# Step 2: Submit block order
order_request = {
"clOrderId": "fb45ac11-584a-4c31-93ae-6db3c0fb1547",
"symbol": "ETH-USD",
"side": "SELL",
"currency": "ETH",
"quantity": "0.226",
"orderType": "LIMIT",
"limitPrice": "2100",
"timestamp": "2024-01-26T19:31:55Z",
"allocation": [
{ "subaccountId": "e3523a44-0a16-4923-8c65-5bd3c0fe5513", "quantity": "0.128" },
{ "subaccountId": "82962476-6250-443e-bcda-1bf6f959ebcd", "quantity": "0.098" }
]
}
response = requests.post(
"https://api.anchorage-staging.com/v2/trading/order",
json=order_request,
headers=request_headers
)
data = response.json()["data"]
# Step 3: Check order status
order_id = "1a69504c1-18ae-9fb4-a4ea-9f83699"
response = requests.get(
f"https://api.anchorage-staging.com/v2/trading/orders/{order_id}",
headers=request_headers
)
data = response.json()["data"]
# check orderStatus, avgPx, fee
```
# Configure webhooks
Source: https://docs.anchorage.com/knowledge-base/platform/developers/webhooks/webhooks-configure
Set up webhook endpoints, subscriptions, and signature validation for event-driven notifications.
Webhooks are enabled by Anchorage Digital upon request. Notify your integration point of contact to enable webhooks for your organization.
## Managing webhooks from the dashboard
Step-by-step instructions and screenshots for creating and managing webhooks in the web dashboard are coming soon.
For payload schema, signature validation, and code samples for a programmatic setup, see the API instructions below.
## Subscribing to webhooks via API
### API permission group configuration
Update your permission group to include the global permission **Configure webhooks**. Either create a new permission group or edit an existing one.
See [Permission Groups](/knowledge-base/platform/developers/permission-groups) for instructions.
### Webhook validation key
The webhook validation key is a hex-encoded Ed25519 public key used to verify the `Api-Signature` header on incoming notifications. Retrieve it via the API and keep this value tamper-proof.
* [Read webhook validation key](/knowledge-base/api-reference/v2/webhook-notifications/get-webhook-validation-key)
The API returns the key as a hex string (64 characters representing 32 bytes). This is the same format used in the code samples below.
### Idempotency with `message_id`
Each message includes a `message_id` — treat it as an idempotent ID to detect duplicate deliveries. Also use `timestamp` to validate event freshness. For details on retry behavior, timeout requirements, and best practices, see [Delivery and reliability](/knowledge-base/platform/developers/webhooks/webhooks-delivery).
### Webhook schema
| Field | Description |
| :----------- | :-------------------------------------------------------------------------------------------------- |
| `payload` | Base64-encoded payload containing the relevant `transactionId` or other IDs depending on event type |
| `timestamp` | Unix timestamp of when the message was sent |
| `message_id` | Unique ID for this event message — use as idempotent ID |
| `event_type` | The event topic and name for the subscription |
```json Schema theme={null}
{
"payload": "[]byte",
"timestamp": "int64",
"message_id": "string",
"event_type": "string"
}
```
### Create a webhook endpoint
* [Create webhook endpoint](/knowledge-base/api-reference/v2/webhook-notifications/create-webhook-endpoint)
* [List webhook endpoints](/knowledge-base/api-reference/v2/webhook-notifications/list-webhook-endpoint)
### List available event types
List the full set of event types configured for your organization before creating subscriptions.
* [Get webhook event types](/knowledge-base/api-reference/v2/webhook-notifications/list-webhook-event-types)
```json Example response theme={null}
{
"data": [
{
"description": "Notification of a new RIA program customer who has successfully completed and passed Onboarding KYC.",
"id": "program-customer-onboard.completed"
},
{
"description": "Notification of a successful withdrawal completed on-chain",
"id": "withdrawal.completed"
},
{
"description": "Notification of a subaccount that currently is low on funds",
"id": "subaccount.low-balance"
},
{
"description": "Notification of a failed transfer",
"id": "transfer.failed"
},
{
"description": "Notification of successful completion of deposit attribution",
"id": "deposit.attributed"
},
{
"description": "Notification of a successful withdrawal initiated but still pending quorum approval and/or risk review",
"id": "withdrawal.initiated"
},
{
"description": "Notification of a collateral package state change",
"id": "collateral-package-state-change.collateral-package-state-change"
},
{
"description": "Notification of a successful transfer that is now completed",
"id": "transfer.completed"
},
{
"description": "Notification of an open RIA program customer process that has requested further information.",
"id": "program-customer-onboard.rfi"
},
{
"description": "Notification of a new deposit pending attribution",
"id": "deposit.pending-attribution"
},
{
"description": "Notification of a failed withdrawal",
"id": "withdrawal.failed"
},
{
"description": "Notification of a subaccount withdrawal request status change",
"id": "subaccount.subaccount-withdrawal-request-status-change"
},
{
"description": "Notification of a transfer that has successfully been initiated",
"id": "transfer.initiated"
},
{
"description": "Notification of a subaccount that has successfully completed and passed Onboarding KYC.",
"id": "subaccount.opened"
}
],
"page": {
"next": null
}
}
```
### Create webhook subscriptions
Subscribe an endpoint to one or more event types. A notification is sent to all subscribed endpoints each time the event fires.
* [Create webhook subscriptions](/knowledge-base/api-reference/v2/webhook-notifications/create-webhook-subscriptions)
* [List webhook subscriptions](/knowledge-base/api-reference/v2/webhook-notifications/list-webhook-endpoint-subscriptions)
### Validate the signature and decode the payload
Every webhook request includes an `Api-Signature` header containing a hex-encoded Ed25519 signature. The signature is computed over the **raw HTTP request body** exactly as received — no timestamp prefix, no additional framing.
To verify:
1. Hex-decode the `Api-Signature` header value to get the raw signature bytes.
2. Verify the signature against the raw request body using the Ed25519 validation key.
3. Base64-decode the `payload` field inside the JSON body to get the event data.
* [Base64 decode tool](https://www.base64decode.org/)
* [Ed25519 signature verification tool](https://cyphr.me/ed25519_tool/ed.html)
```javascript JavaScript theme={null}
import * as ed from '@noble/ed25519';
const pubKey = 'c14b7f3da18abb17b7304f925a68b18c1ea0dad6663b6b54cb67a737ecb77cd0';
function toHex(str: string) {
var result = '';
for (var i = 0; i < str.length; i++) {
result += str.charCodeAt(i).toString(16);
}
return result;
}
const message = `...`; // raw message body
const signature = '...'; // Api-Signature header value
const isValid = await ed.verifyAsync(signature, toHex(message), pubKey);
console.log("Is valid: ", isValid);
console.log("Payload: ", atob(JSON.parse(message).payload));
```
```python Python theme={null}
from http.server import BaseHTTPRequestHandler, HTTPServer
from nacl.exceptions import BadSignatureError
from nacl.encoding import HexEncoder
from nacl.signing import VerifyKey
import base64
import json
publicKey = VerifyKey(
"c14b7f3da18abb17b7304f925a68b18c1ea0dad6663b6b54cb67a737ecb77cd0",
encoder=HexEncoder
)
class MyServer(BaseHTTPRequestHandler):
def do_POST(self):
signature = HexEncoder.decode(self.headers.get("Api-Signature"))
content_len = int(self.headers.get('Content-Length'))
message = self.rfile.read(content_len)
try:
publicKey.verify(message, signature)
except BadSignatureError:
print("Invalid signature")
payload = base64.b64decode(
json.loads(message)["payload"].encode('utf-8')
).decode('utf-8')
print("Payload", payload)
self.send_response(200)
self.end_headers()
```
***
## Payload encryption (optional)
By default, webhook payloads are sent as plaintext JSON signed with the `Api-Signature` header. For an additional layer of security, you can enable ECIES payload encryption by registering a secp256k1 public key with your endpoint.
### How it works
When you register an endpoint with a `public_key`, Anchorage Digital encrypts the entire webhook payload using ECIES (Elliptic Curve Integrated Encryption Scheme) with your secp256k1 public key before delivery. The encrypted request differs from a standard webhook in two ways:
| | Standard webhook | Encrypted webhook |
| :-------------- | :--------------------------- | :---------------------------- |
| `Content-Type` | `application/json` | `application/octet-stream` |
| Body | JSON (`WebhookMessage`) | ECIES ciphertext |
| `Api-Signature` | Signature over the JSON body | Signature over the ciphertext |
To process an encrypted webhook:
1. Verify the `Api-Signature` against the raw request body (the ciphertext).
2. Decrypt the body using your secp256k1 private key to recover the JSON `WebhookMessage`.
3. Base64-decode the `payload` field inside the decrypted JSON.
### Key format
The `public_key` field must be a **PEM-encoded secp256k1 public key**. This is different from the validation key, which is returned as a hex-encoded Ed25519 key.
| Key | Format | Purpose |
| :------------------ | :------------------------------------------------------- | :----------------------------- |
| Validation key | Hex-encoded Ed25519 (from `GET /webhook/validation-key`) | Verify `Api-Signature` headers |
| Endpoint public key | PEM-encoded secp256k1 (provided by you) | Encrypt webhook payloads |
To enable encryption, include the `public_key` field when [creating](/knowledge-base/api-reference/v2/webhook-notifications/create-webhook-endpoint) or [updating](/knowledge-base/api-reference/v2/webhook-notifications/update-webhook-endpoint) your webhook endpoint. To disable encryption, remove the `public_key` from the endpoint configuration.
***
## Manage endpoints and subscriptions
Once configured, update or cancel webhook endpoints and subscriptions as needed.
* [Get webhook endpoint config](/knowledge-base/api-reference/v2/webhook-notifications/get-webhook-endpoint-config)
* [Update webhook endpoint](/knowledge-base/api-reference/v2/webhook-notifications/update-webhook-endpoint)
* [Cancel webhook subscription](/knowledge-base/api-reference/v2/webhook-notifications/cancel-webhook-subscription)
***
## Additional resources
* [Webhook standards](https://webhooks.fyi/learn-more/standards)
* [Webhook consumer best practices](https://webhooks.fyi/best-practices/webhook-consumers)
# Delivery and reliability
Source: https://docs.anchorage.com/knowledge-base/platform/developers/webhooks/webhooks-delivery
Understand retry behavior, delivery guarantees, timeout requirements, and best practices for consuming webhooks.
Anchorage Digital webhooks use at-least-once delivery. Every event notification is retried until your endpoint confirms receipt with a successful response, or until the retry limit is reached. Because webhooks carry money-movement events, we recommend designing your consumer for reliability from the start.
## Delivery guarantees
Anchorage Digital guarantees **at-least-once delivery** for every webhook event. This means:
* Every event fires at least one delivery attempt to each subscribed endpoint.
* The same event may be delivered more than once. Use the `message_id` field to deduplicate.
* Events are not guaranteed to arrive in the order they occurred. Your consumer should handle out-of-order delivery gracefully.
## Retry behavior
We redeliver on any non-2xx response, including 5xx errors, connection failures, and timeouts. Successful delivery requires an HTTP 2xx response from your endpoint.
| Parameter | Value |
| :----------------- | :---------------------------------------------------- |
| Retry attempts | Up to 50 per event |
| Backoff strategy | Exponential, starting at 1 second |
| Maximum interval | 2 hours between attempts |
| Total retry window | 75+ hours |
| Final status | Permanently canceled after all attempts are exhausted |
After all retry attempts are exhausted, the notification is permanently canceled and won't be redelivered. The endpoint registration stays active and continues to receive future events.
We don't auto-disable endpoints after consecutive failures. Failed notifications are canceled individually after retry exhaustion, but your endpoint configuration and subscriptions remain unchanged.
## Consumer endpoint requirements
Your endpoint must meet these requirements to receive webhook notifications reliably.
| Requirement | Detail |
| :--------------- | :---------------------------------- |
| Response timeout | Respond within **5 seconds** |
| Success response | Return any HTTP **2xx** status code |
| HTTPS | Endpoint URL must use HTTPS |
Acknowledge the webhook immediately and process the event asynchronously. This keeps your response time well within the 5-second window and prevents retries caused by slow processing.
## Idempotency and deduplication
Each webhook message includes a unique `message_id`. Because at-least-once delivery means duplicates are possible, treat `message_id` as an idempotent key:
1. Store each `message_id` you process.
2. Before processing a new message, check whether you've already handled that `message_id`.
3. Skip duplicate messages to avoid double-processing.
The `message_id` is a UUID assigned when the event is created. It stays the same across all delivery attempts for that event — if the same message is retried, you'll see the same `message_id`. Each distinct event produces exactly one `message_id`, so you won't receive the same event under different IDs.
The `timestamp` field reflects when each delivery attempt is made, not when the event originally occurred. This means the `timestamp` may differ between retries of the same `message_id`. Use `timestamp` to validate event freshness, but use `message_id` for deduplication.
## Handling out-of-order events
Webhook events may arrive out of order. For example, a `withdrawal.completed` event could arrive before the corresponding `withdrawal.initiated` event if delivery of the first event was delayed by retries.
To handle this:
* Use the `timestamp` field to determine the actual sequence of events.
* Design your state machine to accept transitions from any prior state, not just the immediately preceding one.
* When correlating events to transactions, fetch the current transaction status from the API as the source of truth rather than relying solely on webhook event order.
For details on correlating webhook events to transactions, see [Track transaction status](/knowledge-base/platform/developers/move-money/operate/track-status).
## Monitoring and failure notifications
We don't send automatic alerts when individual notifications exhaust their retries. Delivery status is tracked internally for incident investigation.
To monitor webhook health on your side:
* Log every incoming webhook and its `message_id`.
* Track the gap between the event `timestamp` and your receipt time to detect delivery delays.
* Periodically reconcile webhook events against API transaction data to catch any missed notifications. Use [List transactions](/knowledge-base/api-reference/v2/transactions/list-transactions) to fetch the latest state.
## Validation key
The webhook validation key is a hex-encoded Ed25519 public key used to verify the `Api-Signature` header. You can retrieve it at any time via the [Get webhook validation key](/knowledge-base/api-reference/v2/webhook-notifications/get-webhook-validation-key) endpoint.
There is no automatic key rotation. If a key change is required, Anchorage Digital will coordinate directly with affected clients. There is no `key-id` header — the current validation key is always the correct one to use for signature verification.
The validation key (hex-encoded Ed25519) is a different key from the optional endpoint encryption key (PEM-encoded secp256k1). For details on payload encryption, see [Payload encryption](/knowledge-base/platform/developers/webhooks/webhooks-configure#payload-encryption-optional).
## Best practices
* **Respond fast, process later.** Return a 2xx response as soon as you receive the webhook, then process the payload asynchronously. This avoids unnecessary retries.
* **Deduplicate with `message_id`.** At-least-once delivery means you may receive the same event more than once.
* **Validate signatures first.** Always [verify the `Api-Signature` header](/knowledge-base/platform/developers/webhooks/webhooks-configure#validate-the-signature-and-decode-the-payload) before processing any webhook payload.
* **Handle unknown event types gracefully.** New event types may be added over time. Your consumer should ignore unrecognized `event_type` values rather than failing.
* **Reconcile periodically.** Don't rely on webhooks as your only data source for critical flows. Use the API to periodically verify transaction states, especially for money-movement operations.
# Overview
Source: https://docs.anchorage.com/knowledge-base/platform/developers/webhooks/webhooks-overview
Receive event-driven notifications for operations and transactions across crypto and USD.
The Anchorage Digital Webhooks API delivers event-driven notifications for operations and transactions across both crypto and USD. Event notifications are configurable by endpoint and by event type.
For details on retry behavior, delivery guarantees, and consumer requirements, see [Delivery and reliability](/knowledge-base/platform/developers/webhooks/webhooks-delivery).
## Supported events
Not all webhook events appear in every account, some are restricted to specific use cases.
### transfer
**`transfer.initiated`**\
Payload: `transactionId`, [`details`](#transaction-lifecycle-transfers-and-withdrawals)
Transfer initiated. Fires multiple times as the transfer advances — see [Transaction lifecycle](#transaction-lifecycle-transfers-and-withdrawals).
**`transfer.completed`**\
Payload: `transactionId`, [`details`](#transaction-lifecycle-transfers-and-withdrawals)
Transfer successfully completed.
**`transfer.failed`**\
Payload: `transactionId`, [`details`](#failure-reasons)
Transfer failed. See [Failure reasons](#failure-reasons).
### withdrawal
**`withdrawal.initiated`**\
Payload: `transactionId`, [`details`](#transaction-lifecycle-transfers-and-withdrawals)
Withdrawal initiated. Fires multiple times as the withdrawal advances — see [Transaction lifecycle](#transaction-lifecycle-transfers-and-withdrawals).
**`withdrawal.completed`**\
Payload: `transactionId`, [`details`](#transaction-lifecycle-transfers-and-withdrawals)
Withdrawal successfully completed.
**`withdrawal.failed`**\
Payload: `transactionId`, [`details`](#failure-reasons)
Withdrawal failed. See [Failure reasons](#failure-reasons).
### deposit
**`deposit.attributed`**\
Payload: `transactionId`
Deposit attribution completed. Also fires when a USD deposit settles, since fiat deposits don't require attribution.
**`deposit.pending-attribution`**\
Payload: `transactionId`
New deposit pending attribution. Crypto only; fiat deposits don't require attribution.
### program-customer-onboard
Wealth manager only.
**`program-customer-onboard.completed`**\
Payload: `customerId`, `applicationType`
New RIA program customer passed onboarding KYC. Subaccount creation is now available.
**`program-customer-onboard.rfi`**\
Payload: `customerId`
Request for more information on program customer onboarding.
### subaccount
Wealth manager only.
**`subaccount.opened`**\
Payload: `subaccountId`
New RIA program customer subaccount opened.
**`subaccount.subaccount-withdrawal-request-status-change`**\
Payload: `transactionId` (subaccount tx)
Subaccount withdrawal request status changed.
**`subaccount.low-balance`**\
Payload: `subaccountId`
Subaccount balance is low.
### collateral-package-state-change
Collateral management only.
**`collateral-package-state-change.margin-return`**\
Payload: `collateralPackageId`, `state`, `pledgorName`, `securedPartyName`, `exposureId`, `amountReturned`, `currentLTV`, `marginReturnThresholdLTV`, `marginReturnReturnToLTV`
Package LTV fell below the defined MarginReturn LTV.
**`collateral-package-state-change.margin-call`**\
Payload: `collateralPackageId`, `state`, `pledgorName`, `securedPartyName`, `exposureId`, `currentLTV`, `amountRequired`, `marginCallThresholdLTV`, `actionRequired`, `cureDeadline`
Package LTV exceeded the defined MarginCall LTV.
**`collateral-package-state-change.healthy`**\
Payload: `collateralPackageId`, `state`, `pledgorName`, `securedPartyName`, `exposureId`, `currentLTV`
Package LTV returned to the healthy range.
**`collateral-package-state-change.critical`**\
Payload: `collateralPackageId`, `state`, `pledgorName`, `securedPartyName`, `exposureId`, `currentLTV`, `criticalThresholdLTV`
Package LTV exceeded the defined Critical LTV.
**`collateral-package-state-change.cure-period-expired`**\
Payload: `collateralPackageId`, `state`, `pledgorName`, `securedPartyName`, `exposureId`, `curePeriod`, `action`
Margin call cure deadline passed.
**`collateral-package-state-change.accelerated-margin-call`**\
Payload: `collateralPackageId`, `state`, `pledgorName`, `securedPartyName`, `exposureId`, `currentLTV`, `amountRequired`, `actionRequired`, `cureDeadline`
Accelerated margin call issued.
**`collateral-package-state-change.cm-operation-created`**\
Payload: `collateralPackageId`, `state`, `pledgorName`, `securedPartyName`, `exposureId`
New collateral management operation created.
**`collateral-package-state-change.package-defaulted`**\
Payload: `collateralPackageId`, `state`, `pledgorName`, `securedPartyName`, `exposureId`, `currentLTV`, `defaultNoticeWarning`
Package entered the defaulted state.
### trade-order
**`trade-order.execution-report`**\
Payload: *(varies)*
Trade order execution report received.
### tax
**`tax.transaction-tagged`**\
Payload: `transactionId`, `state`, `warnings`
Tax lot tagging applied to a transaction.
**`tax.transaction-untagged`**\
Payload: `transactionId`, `state`
Tax lot tagging removed from a transaction.
## Transaction lifecycle (transfers and withdrawals)
For `transfer` and `withdrawal`, the three events, `initiated`, `completed`, and `failed`, track an operation across its whole lifecycle. Unlike other topics, `initiated` fires more than once: each time the operation reaches a new phase, a fresh `initiated` event arrives with a different `details` value. Read `details` to know where the operation is. `completed` fires once on success, and `failed` fires once on a terminal failure, each with its own `details` value.
Expanded lifecycle `details` are rolling out per organization. If you don't yet see a `details` field on your `transfer` and `withdrawal` events, notify your integration point of contact.
Each `initiated` event carries one of these `details` values:
| `details` | Fires when | Still cancelable? |
| :---------------------------------- | :----------------------------------------------------------------- | :---------------- |
| `queued` | Operation created, waiting on quorum approval and/or risk review | Yes |
| `quorum-met` (withdrawals only) | Quorum approvals gathered, handed to Anchorage Digital risk review | Yes |
| `signing` | Risk review passed, transaction signing begins | Yes |
| `broadcasting` (committed on-chain) | Transaction broadcast to the network | No |
The `completed` event carries a single `details` value, `completed`, once the operation settles successfully.
### Failure reasons
A `failed` event fires once if the operation ends unsuccessfully, carrying one of these `details` values:
| `details` | Meaning |
| :--------- | :------------------------------------------------------------------ |
| `rejected` | An approver or Anchorage Digital risk review rejected the operation |
| `expired` | The operation timed out before completion |
| `canceled` | The operation was canceled |
Some `failed` events arrive with no `details` field. Treat a missing `details` as an unspecified failure.
Because `initiated` now fires multiple times, order matters. Webhook delivery is at-least-once and events may arrive out of order, so use `details` rather than arrival order to track progress. See [Delivery and reliability](/knowledge-base/platform/developers/webhooks/webhooks-delivery) for handling duplicates and out-of-order events.
# Webhook testing
Source: https://docs.anchorage.com/knowledge-base/platform/developers/webhooks/webhooks-sandbox
Step-by-step guide to testing webhooks in the Anchorage Digital sandbox environment.
Either create your own endpoint or use the [Svix playground](https://www.svix.com/play/) for rapid testing.
Once you have an endpoint, register it via API or the web dashboard:
* **API:** [Create a webhook endpoint](/knowledge-base/api-reference/v2/webhook-notifications/create-webhook-endpoint) — use the `url` field to register the endpoint.
* **Web dashboard:** [Create webhooks](https://clientdashboard.anchorage-staging.com/webhooks/)
* **API:** [List webhook event types](/knowledge-base/api-reference/v2/webhook-notifications/list-webhook-event-types)
* **API:** [Create webhook subscriptions](/knowledge-base/api-reference/v2/webhook-notifications/create-webhook-subscriptions) — use the `endpointId` to subscribe to any or all event types.
* **Web dashboard:** [Select events](https://clientdashboard.anchorage-staging.com/webhooks/)
The validation key is used to verify that webhook messages originate from Anchorage Digital. Find it on the web dashboard or via API.
**Sandbox validation key:**
```text theme={null}
c14b7f3da18abb17b7304f925a68b18c1ea0dad6663b6b54cb67a737ecb77cd0
```
* **API:** [Get webhook validation key](/knowledge-base/api-reference/v2/webhook-notifications/get-webhook-validation-key)
To test in sandbox, send testnet assets to a wallet, or attempt a withdrawal or transfer via API or the iOS app.
For a deposit event:
1. Generate a new wallet address for BTC Signet (`BTC_S`) via Postman or the API reference.
2. Use the [BTC Signet Faucet](https://signetfaucet.com/) to send testnet BTC to that address.
Once the event fires, your endpoint will receive a message like the following:
```json Deposit theme={null}
{
"payload": "eyJ0cmFuc2FjdGlvbklkIjoiNjE4Y2JkNTVlNzE2ZmFlMGVkODNjYTcyOWM4MDI2NmEifQ==",
"timestamp": 1729112450,
"message_id": "aa2dbc06-1665-44c0-bb8e-d2b0ad15a564",
"event_type": "deposit.pending-attribution"
}
```
```json KYC completed theme={null}
{
"payload": "eyJjdXN0b21lcklkIjoiZmJmMzYwOTlkZTMzNmQwMzkyODU0ZmQ5ZTY4NjQxMDcyMjFkYmRhMzBhOWQ1ZWQ4YWI1NWE4ZmZmNTU2NWY3MSIsImFwcGxpY2F0aW9uVHlwZSI6IlJJQV9QQ19JTlNUSVRVVElPTiJ9",
"timestamp": 1729621585,
"message_id": "0b136ab6-f837-4de4-9cd8-f8c3c122f443",
"event_type": "program-customer-onboard.completed"
}
```
Verify the webhook message is from Anchorage Digital using the validation key and the API signature header.
You can validate manually or use an open-source tool:
[Ed25519 signature tool](https://cyphr.me/ed25519_tool/ed.html)
The `Api-Signature` header is hex-encoded. Decode it to raw bytes before verifying.
| Field | Value |
| :----------------- | :------------------------------------- |
| Message encoding | Text (UTF-8) |
| Message | Paste the raw request body |
| Key encoding | Hex |
| Seed (private key) | Leave blank |
| Public key | Validation key |
| Signature encoding | Hex |
| Signature | Paste the `Api-Signature` header value |
The `payload` field in the response body is Base64-encoded. Decode it to retrieve the event data.
Use a [Base64 decode tool](https://www.base64decode.org/) — paste the `payload` value into the decode input.
Use the decoded `transactionId` (or `customerId` for KYC events) to fetch full details from the API:
* [List transactions](/knowledge-base/api-reference/v2/transactions/list-transactions)
* *(RIA only)* [Get KYC onboarding status](/knowledge-base/api-reference/v2/onboarding/retrieve-uploaded-data-and-status-of-customer-onboarding)
# Account hierarchy
Source: https://docs.anchorage.com/knowledge-base/platform/users/account-hierarchy
Understand how organizations, accounts, vaults, wallets, and addresses fit together.
Anchorage Digital organizes your assets in a hierarchical structure. Each level has its own role, and understanding how they connect helps you set up vaults, wallets, and permissions effectively.
## Organizations
The **organization** is the top level of the hierarchy — it represents your institution's relationship with Anchorage Digital. An organization can contain one or many accounts.
## Accounts
Each organization can have multiple **accounts**. An account can represent its own legal entity under the parent organization, or a division of the parent organization. This lets you onboard separate business entities while keeping asset ownership separate at the account level.
For organizations serving their own end clients (B2B2B or B2B2C use cases), accounts can also represent end customers under your control. See [B2B2X accounts](/knowledge-base/platform/users/b2b2x-accounts) for details on structuring multi-client accounts.
## Vaults
Under each account, there may be one or many **vaults**. A vault is how you organize wallets and control who can access and transact with the assets inside.
Each vault has its own security and quorum approval policy. Administrators choose who manages each vault and how many members constitute a quorum for sensitive operations. Vaults can hold single or multiple assets depending on your needs.
See [Creating vaults](/knowledge-base/platform/users/creating-vaults) for setup instructions and [Vault policies](/knowledge-base/platform/users/vault-policies) for configuring approval rules.
## Wallets
Each vault contains one or more **wallets**. A wallet holds a specific asset and provides the deposit addresses you share with counterparties.
Wallets work differently depending on the blockchain model:
* **Account-based wallets** (e.g., Ethereum) contain a single address shared across all tokens on that network. ETH and ERC-20 tokens in the same wallet use the same deposit address.
* **UTXO wallets** (e.g., Bitcoin) can have multiple addresses, all pooled to the same wallet. New addresses are generated automatically during transactions to handle change.
A vault can hold multiple wallets for the same blockchain, which is useful for segregating assets by counterparty or purpose. The first wallet created for each blockchain in a vault is designated the **default wallet**, which is used for external withdrawals, trade settlement, and API holds.
Each vault can hold only one USD wallet. See [USD banking](/knowledge-base/platform/users/usd-banking) for details on fiat wallets.
See [Wallet creation](/knowledge-base/platform/users/wallet-creation) for how to create wallets and manage addresses.
## Balances
Each asset in a vault carries two balances:
* **Available balance** — funds you can withdraw, transfer, or stake right now. This excludes any funds that are held, in progress, or locked.
* **Total balance** — the total amount of the asset under custody, including funds that are pending, locked for voting, or otherwise in transition. This is always greater than or equal to the available balance.
For a detailed breakdown of what each balance label means in the web dashboard, see [Reading balances](/knowledge-base/platform/users/reading-balances).
# Adding users
Source: https://docs.anchorage.com/knowledge-base/platform/users/adding-users
Add and onboard new users to your organization.
Administrators with user management permissions can add new users to an organization and generate enrollment QR codes. New users must have the Anchorage Digital iOS app downloaded before they can complete enrollment.
Only administrators with user management permissions are able to add new users to an organization and generate enrollment QR codes.
This flow covers an existing administrator adding a user to an organization—sandbox or production. The admin generates the enrollment QR code, and the new user scans it before completing KYC. Initial account seeding for a brand-new organization differs: there, the enrollment QR is issued after KYC clears—see [Onboarding your organization](/knowledge-base/platform/users/onboarding-organization).
## Generating a QR code
In the iOS app, tap the **gear icon** (Settings), then tap **Team**, and select **Add new user**.
Tap **Add user** and submit your biometric authentication to proceed.
Select the permission level for the new user. Choose the role before tapping **Continue**, then select the vault policies to which the user will have access.
Review the permissions assigned across each role, then tap **Continue**.
Continue following the prompts until a QR code is generated. Share the QR code with the new user. If the administrator and the new user cannot physically meet, the administrator can email the enrollment QR code to the new user or share it securely another way.
A user has access only to the vault policies you assign. If no vault policy is assigned, the user can land as a Viewer until one is added—upgrade them later in the vault under **Users**. See [Managing users](/knowledge-base/platform/users/managing-users). Add-user operations expire if they aren't approved promptly; if one expires, start it again.
## New user enrollment
Once the new user has the QR code and the app installed, they complete the following steps:
The new user downloads the Anchorage Digital iOS app, reviews, and accepts the disclaimers until prompted to scan a QR code.
Tap **Next** to begin allowing access, then tap **Continue**. Scan the QR code, then tap **Accept** and **Continue**.
The new user completes the iOS app facial and voice recognition setup. All future verifications will be checked against this original biometric pattern.
Tap **Continue** and submit biometric authentication.
## KYC process
After completing biometric setup, the new user must complete a Know Your Customer (KYC) verification.
The new user receives an email with a link to complete the KYC form. Open the email and click **Open application** to begin the KYC process and submit the form with personal information.
Complete the KYC form on a desktop browser. The form is not currently supported on mobile.
Quorum administrators with user management permissions will receive a notification to approve the **Add user** operation. This triggers an Anchorage Digital review and approval request.
Once the operation is approved by the required quorum and reviewed by Anchorage Digital, the new user can log in.
The new user must accept the request to perform KYC and input preliminary personal information during the enrollment scan step. Any future verifications will be checked against the original facial and voice recognition pattern established during setup.
# Administrator policy
Source: https://docs.anchorage.com/knowledge-base/platform/users/administrator-policy
Customize rules and users for administrator-level operations.
Organization-level operations default to the **Any admin operations** rule, unless administrators add specific rules for User management, Trusted destination, Vault, or API management operations.
Administrator policy rules always resolve to quorum approval. The **Block** outcome is available on vault policies only, so organization-level operations can't be blocked outright — see [Outcomes](/knowledge-base/platform/users/rules#outcomes).
Any changes to the administrator policy are subject to quorum approval. You'll be prompted to submit biometric approval on your iOS device.
To customize your administrator policy, tap **Settings**, then **Policies**, and select **Admin policy**. From here, you can configure **Rules** and **Users**.
## Base quorum members
The base quorum defines the pool of administrators eligible to approve operations under the administrator policy.
### Editing base quorum members
Tap **Rules**, then tap the three-dot menu next to the rule you want to edit and select **Edit rule**.
In **Edit rule**, tap the **Quorum is** field, select the members who can approve operations under this rule, and tap **Continue**.
Tap **Done** to save the rule. Follow the prompts to submit biometric approval — quorum approval is required.
Other administrators will receive a notification to approve the action. Once quorum is met, Anchorage Digital will review the operation.
## Base quorum approvals
The approval limit defines how many base quorum members must approve an operation before it can proceed.
### Editing base quorum approvals
Tap **Rules**, then tap the three-dot menu next to the rule you want to edit and select **Edit rule**.
In **Edit rule**, use the stepper under **Number of approvals required** to set how many quorum members must approve.
Tap **Done** to save the rule. Follow the prompts to submit biometric approval — quorum approval is required.
## Sub-quorums
Sub-quorums add an additional layer of approval security. Each sub-quorum establishes a prerequisite: any operation falling under the policy cannot be completed without a preset number of approvals from the designated sub-quorum members.
Administrators can add as many sub-quorums as needed for each account-level policy.
### Adding a sub-quorum
Tap **Rules**, then tap the three-dot menu next to the rule you want to edit and select **Edit rule**.
In **Edit rule**, tap **Add sub-quorum**.
From the base quorum's approver pool, select at least one member for the sub-quorum and tap **Continue**.
Set the number of approvals this sub-quorum requires and tap **Continue**.
Give the sub-quorum a name and an optional description, then tap **Finish**.
Back in **Edit rule**, confirm the new sub-quorum, then tap **Done**. Follow the prompts to submit biometric approval — quorum approval is required.
### Editing sub-quorum details
Administrators may update a sub-quorum's name and description if circumstances change.
Tap **Rules**, then tap the three-dot menu next to the rule you want to edit and select **Edit rule**.
Tap the three-dot menu next to the sub-quorum you want to edit and select **Edit details**.
Update the **Sub-quorum name** or description as needed, then tap **Finish**.
Back in **Edit rule**, tap **Done**. Follow the prompts to submit biometric approval — quorum approval is required.
### Editing sub-quorum members
Tap **Rules**, then tap the three-dot menu next to the rule you want to edit and select **Edit rule**.
Tap the three-dot menu next to the sub-quorum, select **Edit members**, then update the selected members and tap **Continue**.
Back in **Edit rule**, tap **Done**. Follow the prompts to submit biometric approval — quorum approval is required.
### Editing sub-quorum approvals
Tap **Rules**, then tap the three-dot menu next to the rule you want to edit and select **Edit rule**.
Tap the three-dot menu next to the sub-quorum, select **Edit approval limit**, choose the number of required approvers, and tap **Save**.
Back in **Edit rule**, tap **Done**. Follow the prompts to submit biometric approval — quorum approval is required.
### Deleting a sub-quorum
Tap **Rules**, then tap the three-dot menu next to the rule you want to edit and select **Edit rule**.
Tap the three-dot menu next to the sub-quorum and select **Delete**.
Back in **Edit rule**, tap **Done**. Follow the prompts to submit biometric approval — quorum approval is required.
## Reset to default policy
You can reset a customized administrator policy back to the default configuration at any time.
Tap the policy you want to reset.
Select **Reset to default policy** and follow the prompts.
Select **Reset to default policy** again and confirm that you want to reset.
Tap **Finish and review** and follow the prompts to submit biometric approval — quorum approval is required.
# Approvals and quorum
Source: https://docs.anchorage.com/knowledge-base/platform/users/approvals-quorum
Approve operations, find pending requests, and resolve approvals that are stuck.
Sensitive operations need quorum approval before Anchorage Digital processes them. This guide explains how to approve, where pending requests appear, and what to do when one is stuck.
## How approvals work
When you initiate an operation, you also approve it in the Anchorage Digital iOS app, on the same device that generated your enrollment QR code. Other members of the relevant policy's quorum approve from their own enrolled devices. Pending operations appear under **Pending activity** (the bell icon). For how quorums are configured, see [Vault policies](/knowledge-base/platform/users/vault-policies) and [Rules](/knowledge-base/platform/users/rules).
## Approve a pending operation
In the iOS app, go to **Pending activity** (bell icon) to see the operations awaiting approval.
Tap the operation you want to approve. To approve several at once, tap **Select**, choose the operations, and tap **Confirm and review**.
Review the details, then follow the prompts to submit biometric approval — quorum approval is required.
For approving several operations at once, see [Batched endorsements](/knowledge-base/platform/users/sending-assets#batched-endorsements).
## Approval windows and expiry
Approval requests don't stay open indefinitely. Each stage of the process has its own window, and an operation that doesn't collect what it needs in time expires.
| Stage | Window |
| :----------------------------------------- | :------------- |
| Initiator endorsement | About 1 hour |
| Initiator endorsement, add user operations | About 24 hours |
| Remaining quorum approvals | 14 days |
An expired operation leaves the pending queue without being rejected, so it's easy to miss. If a user you added never gained access, or an operation you were waiting on is no longer in the queue, check whether it expired. Expired operations can't be revived, so you'll need to initiate a fresh one.
## Why is my operation stuck pending?
A pending operation is waiting on quorum. Work through these checks:
* **It was blocked, not stuck** — an operation rejected by a rule with a Block [outcome](/knowledge-base/platform/users/rules#outcomes) doesn't wait for approval. It's declined immediately and won't appear under Pending activity.
* **Quorum isn't met yet** — confirm who in the policy still needs to approve.
* **An endorsement error** — an outdated app version can block approval. Update the app, then try again. See [Updating the app](/knowledge-base/platform/users/mobile-app#updating-the-app).
* **Anchorage Digital review** — some operations route to Anchorage Digital for review after quorum is met, so they can stay pending briefly before completing. Review usually finishes within about 30 minutes, though periods of high volume can stretch that.
If an operation has been in review well beyond that, or you have a time-sensitive request, email [accountexecutive@anchorage.com](mailto:accountexecutive@anchorage.com) so we can prioritize it.
You can only endorse an operation you initiated on the device that generated your enrollment QR code. If you've moved to a new device, see [Device and login recovery](/knowledge-base/platform/users/device-login-recovery).
# Asset registry
Source: https://docs.anchorage.com/knowledge-base/platform/users/asset-registry
Look up any asset in the registry to see which Anchorage Digital platforms support it for custody, staking, and governance.
Our asset registry covers every asset Anchorage Digital has onboarded. Use this page to check whether an asset is available for custody on your platform, and whether it also supports staking or governance.
## Finding an asset
Assets are listed alphabetically. Search by asset name, asset type, or network ID, then filter by network or by the coverage you're checking for.
Each asset shows its asset type and network ID beneath its name. **ADB** is Anchorage Digital Bank and **ADS** is Anchorage Digital Singapore. Staking and governance availability is the same on both platforms. A few assets support staking or governance without being offered for custody, so their **ADB** and **ADS** columns are empty.
Availability changes as we onboard new assets and retire others. Our registry also holds 81 onboarded assets that aren't offered for custody, staking, or governance today, so they aren't listed above. If you need an asset that isn't listed, see [Requesting asset support](/knowledge-base/platform/users/asset-support-requests).
## What we support today
| | Assets |
| :------------------------------------- | :----- |
| Listed on this page | 988 |
| Custody on Anchorage Digital Bank | 978 |
| Custody on Anchorage Digital Singapore | 623 |
| Staking | 43 |
| Governance | 81 |
# Requesting asset support
Source: https://docs.anchorage.com/knowledge-base/platform/users/asset-support-requests
Request support for a new asset or network and understand what to expect.
If an asset or network you need isn't supported yet, you can request it. This guide explains how to submit a request and what the timeline looks like.
## Submit a request
In the iOS app, check what's supported under **Settings**, then **Supported assets**. If an asset isn't listed, tap **Make a request** to open the asset request form, select the network, and provide the contract address (or asset symbol) before submitting.
For assets that involve smart-contract interactions, you also complete a smart-contract interaction questionnaire so the asset team can assess them. Brand-new networks require a go/no-go evaluation and can't be fast-tracked.
## "Supported" doesn't always mean you can deposit yet
Asset support and deposit-address creation are separate stages. When custody support for an asset is complete, deposit-address creation can still be gated separately, so a supported asset isn't always immediately depositable.
There's no firm client-facing timeline for these stages today. Your client experience team can share where a given asset stands.
# Atlas
Source: https://docs.anchorage.com/knowledge-base/platform/users/atlas-network
Use Atlas for peer-to-peer settlement with trusted counterparties.
Atlas (Anchorage Digital Trusted Liquidity and Settlement) enables institutions to mitigate counterparty risk and enhance capital efficiency through peer-to-peer settlement. All custody clients have access to Atlas.
## What is settlement, and why it matters
Settlement is the moment a trade actually completes — when each side delivers what it owes and the assets change hands. Between agreeing a trade and settling it, every party is exposed to **counterparty risk**: the chance the other side fails to deliver after you've already sent your funds.
The traditional way to reduce that risk is to pre-fund — move your assets onto an exchange or to the counterparty before you trade. That solves trust by giving up control: your assets sit off your balance sheet, outside custody, earning nothing and exposed to the venue's own risk. Inefficient settlement ties up capital and multiplies the places your assets can be lost.
Efficient settlement is the opposite: assets stay safe until the instant both sides are ready, then move together. Less capital tied up, less time exposed, fewer intermediaries.
## How Atlas makes settlement better
With Atlas, both counterparties settle directly from Anchorage Digital custody:
* **No pre-funding a third party.** Your assets never leave custody to sit on an exchange waiting to trade — they move only at settlement.
* **Both sides approve.** Two-sided settlements require quorum approval from each party, so neither side delivers unless the other is committed — removing the "who sends first" problem.
* **Efficient.** Once both parties approve and conditions are met, Atlas processes the settlement directly from custody.
* **Trusted counterparties.** Settle with the Anchorage Digital trading desks and a growing network of sell-side institutions, identified by participant ID.
To take advantage of advanced functionalities such as simultaneous two-way settlements, reach out to Anchorage Digital to sign up for **Atlas Plus**.
## Getting started with Atlas
Create your network participants.
Other network participants will use the ID to settle with your participants.
Search counterparties by participant ID and add them to your trusted counterparties.
Propose and/or accept settlements.
## Setting up participants
### Creating participants
Under **Directory**, go to **Your participants** and click on **+ Create participant**.
Your participant's name will be visible to other network participants when searching by your participant ID. If you wish to use a different name—such as your organization's DBA name—contact your client experience manager.
Select the account you would like to create a participant for. Specify the default settlement vault and wallets per network type, then click **Submit**.
Once created, you will see the list of accounts participating in the network and their corresponding participant IDs. Other counterparties will use this ID to find you and initiate settlements.
## Viewing & sharing participants
In the **Participants** tab, click the participant to see details such as the account name and status. Select **Set or edit** to change the default settlement vault and wallets as applicable.
## Trusted counterparties
Activate your participants for settlement with trusted counterparties, which include the Anchorage Digital trading desks and a growing list of other sell-side institutions.
**Anchorage Digital trading desk participant IDs:**
* Anchorage Hold: `8byj5hvj`
* A1, Ltd.: `7t7wa507`
### Adding a trusted counterparty
Under **Trusted counterparties** in the web dashboard, select **New trusted counterparty** to add participants.
Select the participant you would like to add as a trusted counterparty and search by their participant ID.
Add a description (optional) and select **Submit**. After selecting Submit, quorum approval will be required within the iOS app.
### Reviewing trusted counterparties
Review the status of your trusted counterparties in the **Trusted counterparties** section. Select the three dots to deactivate a counterparty if needed.
## Settling
Under **Settle**, click **+ New settlement** to add a new settlement.
You can submit settlement proposals to:
* **Send funds**
* **Receive funds**
* **Send and receive funds simultaneously** (Atlas Plus clients only)
Settlement proposals require quorum approval in the iOS app, per the vault default policy or withdrawal policy (if any). For **Receive funds** and **Send and receive funds** proposals, the counterparty is also required to submit quorum approval in their Anchorage Digital account.
Ensure that vaults and wallets involved in the transaction are funded and provisioned with sufficient gas for the settlement.
### Proposing a settlement
Select the participant from which you want to propose a settlement.
Search for the counterparty by their participant ID or select them from your list of trusted counterparties.
Select a vault and provide the details of the assets being transferred. Add a reference number (optional) and click **Continue**.
Review the transaction details and click **Propose settlement** to endorse the proposal in the iOS app.
Monitor the status of your proposal and take necessary actions. Ask the counterparty to review and accept the proposed settlement if needed.
The reference number will be visible to your counterparty.
### Accepting a settlement proposal
Settlement proposals received by your organization must be reviewed and approved. Approvals fall under the receiving vault's default quorum policy or withdrawal policy (if applicable).
Click **Review details** to check and confirm the details of the proposed settlement.
Review the settlement details and select a vault to receive the funds.
Proceed to the iOS app to submit your biometrics and await quorum approval.
Once both parties have submitted approval and all necessary conditions are met, the settlement transaction will be processed within one minute from approval to broadcast.
If your organization is only receiving funds and no funds are being sent to the counterparty, biometric approval is not required.
## Email notifications
Receive email notifications for settlement activity. Notification destinations can be configured at the organization level or for individual Atlas participant accounts.
Navigate to **Document delivery** in **Settings** to set up or update your distribution list for settlement network notifications.
# Exploring settlement workflows
Source: https://docs.anchorage.com/knowledge-base/platform/users/atlas-settlement-explorer
Compare one-way send, one-way receive, and two-way settlement flows across leg scope and instruction channel.
# Exploring settlement workflows
Send, receive, and two-way settlements share the same propose, authorize, and accept mechanics, but differ in who has to authorize and when execution can fire. This explorer walks through the exact sequence for any combination of settlement type, leg scope, and instruction channel.
## The four switches
* **Settlement type**: send (one-way), receive (one-way), or two-way. See [Atlas](/knowledge-base/platform/users/atlas-network) for what each workflow means for your organization.
* **Leg scope**: single-leg or multi-leg, meaning how many asset amounts are bundled into one settlement instruction.
* **Instruction channel**: API or UI, meaning whether authorize and accept happen directly against the endpoints, or in the web dashboard under your organization's quorum policy.
* **Gas source**: gas station or wallet-funded, meaning whether the on-chain gas for a leg is topped up from your organization's gas station, or paid from the sending wallet's own balance. USD legs never need gas at all; they settle over Fedwire, not a blockchain.
## Reading the diagram
The proposer and acceptor sit on either side of the Atlas settlement network. Wallet chips light up for the asset or assets actually moving in the current step: one chip under single-leg, several under multi-leg. Solid lines are movement of value or an instruction call; dashed lines are polling or verification. The line that animates is the one active in the current step.
The network node's connected-node chain is an illustrative stand-in for settlement state, not a documented enum. Only **Executing** and **Executed** are states Atlas actually names. Every earlier label just names the step most recently completed.
This walkthrough uses the literal USD wallet alongside two illustrative on-chain stablecoins, USDx\_ETH and USDx\_SOL (not Anchorage Digital tickers). USD is fee-exempt and needs no gas. It settles over Fedwire, not a blockchain. USDx\_ETH and USDx\_SOL are on-chain, so each incurs a network fee and draws gas from either the gas station or the sending wallet, depending on the gas source switch: ETH for USDx\_ETH, SOL for USDx\_SOL.
For how Atlas fits into your organization, see [Atlas](/knowledge-base/platform/users/atlas-network). For the technical endpoint reference, see [Settlement API integration guide](/knowledge-base/platform/developers/atlas/atlas-settlement-api).
# B2B2X account structures
Source: https://docs.anchorage.com/knowledge-base/platform/users/b2b2x-accounts
Choose the right account structure for serving your end clients on Anchorage Digital.
If your organization serves its own end clients — whether businesses (B2B2B) or consumers (B2B2C) — you can build on top of Anchorage Digital's existing organization model. Vaults and wallets with configurable permissions give you the building blocks to segregate, fund, and govern accounts for the clients you serve, without standing up a parallel ledger of your own.
## Key concepts
Here are a few terms used throughout. Both USD and crypto sit on the same organization model — you segregate end clients using vaults and wallets, regardless of asset type.
* **FBO account** — a "for benefit of" arrangement where you hold the account relationship, and the funds within it belong to your end clients. You are the account holder of record.
* **End client** — the client of our client. The party you serve in a B2B2X relationship.
* **Vault** — the top-level container in the organization model. Carries its own permission set and governance (quorum, approvers). See [Vaults & wallets](/knowledge-base/platform/users/vaults-wallets).
* **Wallet** — sits inside a vault and holds a single asset. Every wallet maintains a true balance and transaction history.
A vault holds at most one USD wallet and any number of crypto wallets. This means USD segregation happens at the vault level (one USD wallet each), while crypto can be segregated by adding wallets within a vault.
### How USD and crypto deposits differ
**USD deposits** arrive as wire transfers, which carry a name, address, routing number, and account number. The deposit instructions on a USD wallet today resolve to your organization's legal name as the account holder of record. Named accounts — where deposit instructions bear the end client's name — are in development.
**Crypto deposits** are wallet addresses that follow the chain's standard. There's no name or bank identity attached, so segregation is handled entirely by which wallet maps to which end client.
## Structures available today
| Structure | What it is | Who it's for |
| :----------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------- |
| **Segregated vaults and wallets** | A dedicated vault and wallet for each end client. Each end client is KYC'd by Anchorage Digital. Balances are segregated natively. | Most B2B2X organizations. The default, recommended path. |
| **Omnibus plus your own sub-ledger** | Pooled funds in a single account with per-end-client balances maintained in your own systems. | Organizations approved for a KYC reliance arrangement who run their own sub-ledger. Available by approval. |
### Segregated vaults and wallets
This is the structure most B2B2X organizations use and the one we recommend. Each end client gets their own vault and wallet, so balances are segregated natively. You don't build or maintain a ledger on top.
**How it works:**
1. Submit a KYC package for the end client to Anchorage Digital's compliance team.
2. Once compliance approves, create a vault in the end client's name with a dedicated wallet.
3. The wallet holds a real balance. Deposit instructions on the wallet resolve to your legal name as the account holder of record.
**Recommended setup pattern:**
Because compliance approval is the gating step and vaults today hold a single USD wallet, the cleanest pattern is to pre-provision vault shells:
1. Create vaults in advance as empty shells — unfunded, unnamed, and not exposed to the end client.
2. Assign each vault the permission set it should be governed by (quorum, approvers).
3. Upon KYC approval, name the vault to the end client and put it into use. The USD wallet already exists from vault creation; add crypto wallets as needed.
This keeps you ready to onboard quickly while ensuring no end client can transact before compliance has cleared them.
### Omnibus plus your own sub-ledger
If you're approved for a **KYC reliance arrangement**, you can hold pooled funds in a single account and run your own sub-ledger to track each end client's balance. Two conditions apply:
1. **Reliance approval.** Anchorage Digital's compliance team must approve a reliance arrangement, relying on your KYC program for your end clients. This is granted case by case.
2. **You maintain the sub-ledger.** Anchorage Digital tracks the pooled balance. Per-end-client balances are yours to maintain.
Under reliance, deposits arrive into your account in your name. Anchorage Digital doesn't see which end client each deposit belongs to — that attribution lives in your sub-ledger.
Most organizations that want native per-end-client identification without running their own sub-ledger are better served by segregated vaults and wallets today, or by named accounts once available.
## Choosing your structure
* **You want Anchorage Digital to segregate and KYC each end client, with real per-client balances:** segregated vaults and wallets. Recommended for most organizations.
* **You're a large platform that wants one account and will run your own sub-ledger, and you can qualify for reliance:** omnibus plus reliance.
* **You need end clients to receive wires in their own name:** named accounts, once available. Use segregated vaults and wallets in the meantime.
## What's coming
* **Named accounts** — sub-accounts that carry the end client's own name and deposit instructions, so end clients receive wires addressed directly to them. In active development.
* **True virtual accounts** — pass-through deposit instructions in the end client's name where Anchorage Digital doesn't maintain the end client's balance. A known future need, not currently being built.
If a true virtual account or native sub-ledger is a hard requirement, contact your Anchorage Digital relationship manager so we can factor it into prioritization.
# Platform capabilities
Source: https://docs.anchorage.com/knowledge-base/platform/users/capabilities
Understand full capabilities and what you can do with the Anchorage Digital platform.
## Mobile app
The Anchorage Digital app uses the security hardware built into modern iPhones to generate and protect each user's signing key on the device. The key is designed so it isn't exposed to apps or transmitted off the device, and using it to sign requires the user's biometrics. This turns a device you already carry into a hardware-backed security key, with no shards to manage and no key ceremonies to run.
Submit operations for review or endorse with no shards or key ceremonies.
Review and endorse operations in under 60 seconds.
Always at hand with no risk of losing anything important.
## Why hardware-backed security matters
Most wallets ask you to trust a password, a seed phrase, or a server. Any of those can be phished, leaked, or copied. Anchorage Digital ties every approval to a specific person on a specific device, enforced in hardware.
Private keys live in tamper-resistant hardware and are used to sign without being exposed outside it — minimizing what an attacker could capture in transit or at rest.
Every sensitive action is bound to a real person's biometrics, not a reusable secret an attacker can capture.
Quorum approval means no one person — and no one stolen device — can move assets alone.
## Web dashboard
The Anchorage Digital web dashboard provides a master view of account activity.
Monitor account activities with a full view of all operations.
Customize your filters to view account activities accordingly.
Export transaction data for bookkeeping, performance tracking, and analysis.
## How the interfaces work together
The mobile app, web dashboard, and API are designed to complement each other — not to be used in isolation.
The iOS app is the trust anchor for every user. It's where your signing key lives and where sensitive operations are endorsed with biometrics. This applies whether you initiated the operation from the dashboard or the API: every approval that requires a human still routes through the iOS app.
The **web dashboard** builds on that foundation for day-to-day use — monitoring activity, initiating operations, managing settings, and running reports. Administrators also use it to configure permission groups and approve API keys before those keys can be used.
The **API** enables programmatic access once those human-gated setup steps are complete. API keys are scoped to specific permission groups. Once activated, the API can run automated workflows — withdrawals to trusted destinations, staking operations, transfers — within the boundaries your team has approved. See quorum requirements by device in [Security architecture](/knowledge-base/platform/users/security).
## API integration
Anchorage Digital offers a full-featured API for institutions that need to integrate digital asset operations into their own systems. Use it to automate workflows, connect to internal platforms, and build programmatic access to custody, staking, and settlement — all within the same security controls that govern the web dashboard.
Reliable APIs that work seamlessly with your systems.
Customize your API keys with different permissions according to your needs.
Get notified of activity in real time for full two-way integration.
# Changing permission levels
Source: https://docs.anchorage.com/knowledge-base/platform/users/changing-permission-levels
Assign vault Operator access and administrator permissions to users.
## Assigning a user to a vault as an Operator
Administrators with vault management permissions may grant users Operator-level access with privileges to initiate only, or to initiate and approve vault operations.
Tap the desired vault, then tap the **Settings** icon in the upper right corner.
Select the **Users** section to view and edit the users on this vault policy.
Tap **Add user** and select the users you want to add to the vault.
To restrict a user to initiate-only permissions, tap the user, select **Initiate only**, and tap **Save changes**.
After making all changes, tap **Continue**. Add a comment (optional) and tap **Review** to submit the operation. Other administrators will receive a notification to approve. Once quorum is met, Anchorage Digital will review for approval.
## Assigning a user as an administrator
Administrators may increase or decrease a user's permissions to the administrator level by adding them to the administrator policy.
Go to **Policies**, then tap **Administrator policy**.
Select **Users** to view the users on the administrator policy.
Tap **Add user** and select the user or users to add as administrators.
Users can be added with **Initiate only** or **Initiate and approve** permissions. If added with **Initiate and approve**, they'll be added to the default **Any admin operation** rule of the administrator policy.
To configure more granularly which rules the new user is added to, edit the policy's rules before submitting.
Confirm the new users appear on the administrator policy, then tap **Continue**.
Tap **Save changes**, then follow the prompts to submit biometric approval — quorum approval is required. Once quorum is met, Anchorage Digital will review for approval.
## Downgrading an administrator to Operator
Changing a user from administrator to Operator is a two-step change, in this order:
1. Remove the user from the administrator policy. In the iOS app, go to **Policies**, tap **Administrator policy**, open the **Default** rule, and tap **Edit approvers** to remove the user, then submit for quorum approval. From the web dashboard, edit the policy's users under **Settings**, then **Policies**—see [Managing policy users](/knowledge-base/platform/users/web-dashboard/team-policies#managing-policy-users).
2. Assign the user Operator access in each vault they should keep, following [Assigning a user to a vault as an Operator](#assigning-a-user-to-a-vault-as-an-operator) above.
Both changes are quorum-approved. Assigning Operator access in a vault without first removing the administrator policy leaves the user with administrator permissions.
# Responding to compliance RFIs
Source: https://docs.anchorage.com/knowledge-base/platform/users/compliance-rfi
Respond to a request for information (RFI) about a transaction's originator or beneficiary.
As part of transaction due diligence, our compliance team may send you a request for information (RFI) about a specific deposit or withdrawal. RFIs are a routine part of operating on a regulated platform—receiving one doesn't mean anything is wrong with your account.
## What an RFI asks for
An RFI asks you to confirm details about a transaction's originator or beneficiary. Typical requests include:
* The counterparty's full legal name
* Date of birth (for individuals)
* Address
* The virtual asset service provider (VASP) hosting the counterparty address, or confirmation that the address is self-hosted
A **hosted** address is held at another VASP, such as an exchange. A **self-hosted** address is a wallet the counterparty controls directly. For how this distinction affects transfers between VASPs, see [Travel Rule](/knowledge-base/platform/users/travel-rule).
## How to respond
Respond using the questionnaire included with the request, and answer every question as completely as you can. If you're unsure how to answer a question, ask your client experience team before submitting.
## Why funds may be delayed
While a transaction is under review, the related funds may be held until screening completes. Responding promptly with complete information is the fastest way to resolve the review.
# Creating and managing vaults
Source: https://docs.anchorage.com/knowledge-base/platform/users/creating-vaults
Create vaults on iOS and web dashboard, then update, staff, and delete them.
Administrators can create as many vaults as needed for the organization. Vaults can be created from the iOS app or the web dashboard. If initiated from the web dashboard, biometric approval must be submitted via the iOS app. Creating a vault is subject to quorum approval by administrators with vault management permissions—once the vault exists, [creating a wallet](/knowledge-base/platform/users/wallet-creation#creating-a-new-wallet) inside it doesn't require quorum.
## Vault policies
When creating a vault, you assign it a vault policy. A vault policy defines the users, permissions, and approval rules that govern operations within that vault. A single vault policy may be assigned to multiple vaults, so any future changes to the policy apply to all vaults using it.
You can either **use an existing vault policy** (inheriting its users, permissions, and rules) or **create a new vault policy** specifically for the new vault.
### Quorums and sub-quorums
Operations within a vault follow the vault policy's quorum and sub-quorum rules.
* **Quorum**: A group of users with permission to initiate and approve operations (default, governance, staking, or withdrawal).
* **Sub-quorum**: Additional approval layers ensuring operations cannot proceed without a set number of approvals from designated members. Policies may have as many sub-quorums as needed.
**Default requirements:**
* Minimum of 3 members who can initiate and approve operations
* Minimum of 2 approvers per rule
You can customize quorum and sub-quorum requirements per operation type: withdrawal, staking, and governance.
The number of members, approvers, and sub-quorums in each vault policy may be influenced by factors like the use case for each vault—frequent or infrequent withdrawals—and the amount of value in the vault. Requiring a larger quorum for higher values is a common approach.
## Creating a vault on iOS
From the main screen, scroll down and tap **Create new vault**.
Enter the vault name and description, select the account, then tap **Continue**.
Choose to use an **existing vault policy** or **create a new vault policy**.
* **Existing policy**: Reuse the same rules for operation approval, users, and permissions configured for other vaults. Tap **Continue** to proceed.
* **New policy**: Create an entirely new configuration specifically for this vault. Tap **Continue** to proceed.
If creating a new vault policy:
* **Add vault policy users**: Add a group of users with permission to initiate only, or to initiate and approve operations.
* **Set user permissions**: Specify which users may initiate and approve operations and which should only initiate. A minimum of 3 users should be able to initiate and approve.
Set the number of approvers for each operation type, optionally adding rules for specific types (withdrawal, staking, governance), then follow the prompts.
Give the new vault policy a name. Once approved, you can assign it to other vaults later.
Add a comment (optional), review the operation details, and submit biometric approval. Administrators with vault management permissions will be notified to approve the vault creation. Anchorage Digital will then review and finalize the operation, making the vault visible.
## Creating a vault on the web dashboard
On the dashboard, select **Create new vault** on the right side to begin.
Enter the vault name and description, then select the account. Select **Next**.
Select an existing vault policy or create a new one, then select **Next**.
* **Existing policy**: Any future changes to this policy will apply to this vault and any other vaults assigned to it.
* **New policy**: Add at least 3 members who can initiate and approve operations, then select **Next**.
Define the rules for approvals needed per operation type (minimum of 2 approvers per rule).
* Set a base quorum and sub-quorums per policy rule.
* Add rules to adjust approval requirements for specific operation types (withdrawal, governance, staking).
Name your new vault policy. Once approved, you can assign it to new or existing vaults.
Add a comment (optional), preview the changes, and select **Finish and review**. Then use the iOS app to submit the vault for approval.
Vault creation requires quorum approval from administrators with vault management permissions. The vault will only become visible after both quorum approval and Anchorage Digital review are complete.
## Managing vaults
Administrators with vault management permissions may change vault settings. Changes are subject to quorum approval, after which Anchorage Digital will review the operation.
### Updating vault details
To update a vault's name or description, tap the vault you want to adjust, then tap the **settings icon** in the upper right corner. Tap **Edit**, update the vault name and description as necessary, and tap **Save**.
Updating vault details (name and description) does not require biometric approval.
### Managing vault users
Administrators with vault management permissions may add, edit user privileges, or remove users from vaults.
#### Adding users to a vault
To grant a user the ability to operate within a vault, add them and assign the appropriate permissions.
In the iOS app, tap the desired vault, then tap the **settings icon** in the upper right corner and select the **Users** section.
Tap **Add user** and select the user or users to add.
To add all users, tap **Select all** and then **Continue**. Adjust user privileges by selecting a user and changing their permissions from **Initiate and approve** to **Initiate only** as needed, then select **Save changes**.
Once all privilege changes are made, select **Done**. After reviewing the operation, submit biometric approval. Quorum approval is then required.
#### Changing vault user privileges
To modify what actions a user is allowed to perform within a vault:
In the vault settings menu, tap **Users**. Select a user and modify their privileges to either **Initiate and Approve** or **Initiate only**. After tapping **Finish and review**, the operation will go through quorum approval.
#### Removing users from a vault
You can remove one or more users from a vault in a single operation.
In the vault settings **Users** list, tap the **Select** option to choose the users you wish to remove. Select the users and follow the prompts to complete the removal process.
### Deleting a vault
Administrators with vault management permissions can delete vaults that are no longer in use. Once quorum is met, Anchorage Digital will review the operation before proceeding with deletion.
In the vault settings menu, tap **Delete vault**. Add a comment (optional), then tap **Review** to review the operation. Once reviewed, submit it for approval.
# Device and login recovery
Source: https://docs.anchorage.com/knowledge-base/platform/users/device-login-recovery
Replace an iPhone with or without your old device, and reinstall or update the app.
Use this guide to restore access on a new iPhone, or to reinstall or update the Anchorage Digital app:
* [Replacing an iPhone without access to your old device](#replacing-an-iphone-without-access-to-your-old-device)
* [Replacing an iPhone with access to your old device](#replacing-an-iphone-with-access-to-your-old-device)
* [Reinstalling or updating the iOS app](#reinstalling-or-updating-the-ios-app)
## Replacing an iPhone without access to your old device
Use this method if your old iPhone has been lost, stolen, or is otherwise inaccessible. Contact Anchorage Digital to have the old device marked as lost, then an administrator with user management permissions sets up your new device and shares a QR code with you to scan.
If you're keeping the same Apple ID used for the original download, tap your profile in the App Store, then tap **Apps**. Search for **Anchorage Digital** and install. If you're using a different Apple ID, contact [accountexecutive@anchorage.com](mailto:accountexecutive@anchorage.com) for the regular download.
After installing, contact [accountexecutive@anchorage.com](mailto:accountexecutive@anchorage.com) to initiate the device replacement operation. The old iPhone will be marked as lost. Only administrators with user management permissions can initiate and approve the replacement operation.
After Anchorage Digital confirms the device is lost, an administrator goes to **Settings**, taps **Team**, finds you, and taps **Lost device**, then **Set up new device**.
The administrator shares the generated QR code with you to scan on your new device.
The initiating administrator goes to **Activity**, opens the operation, and submits biometric approval.
Other administrators receive a notification to approve. Once quorum is met, Anchorage Digital will review for approval.
## Replacing an iPhone with access to your old device
Use this method if you still have access to your old iPhone and can generate a QR code from it.
If you're keeping the same Apple ID used for the original download, tap your profile in the App Store, then tap **Apps**. Search for **Anchorage Digital** and install. If you're using a different Apple ID, contact [accountexecutive@anchorage.com](mailto:accountexecutive@anchorage.com) for the regular download.
On your old device, go to **Settings**, tap **Replace my device**, and follow the on-screen prompts to generate a QR code.
In the Anchorage Digital app on your new device, scan the QR code generated by your old device and follow the instructions.
Complete biometric authentication on your old device.
Ask the quorum administrators to approve the operation. Once quorum is met, Anchorage Digital will review for approval.
## Reinstalling or updating the iOS app
If your organization's legacy privately distributed app was automatically removed from your device during Anchorage Digital's migration to the public App Store listing, this isn't currently a self-serve fix. Contact [accountexecutive@anchorage.com](mailto:accountexecutive@anchorage.com) or your Relationship Manager so we can restore your access. See [Migrating from the private app](/knowledge-base/platform/users/mobile-app#migrating-from-the-private-app) for background on the migration.
Don't try to work around a removed private app on your own, such as by redownloading it from your Apple ID's purchase history. We haven't confirmed a reliable self-serve path for this scenario, and unverified workarounds have caused organizations to lose quorum.
If you're keeping the same Apple ID used for the original download, a reinstall generally isn't required for a new device. Update the app if needed. See [Updating the app](/knowledge-base/platform/users/mobile-app#updating-the-app).
If you're using a different Apple ID on the new device, contact [accountexecutive@anchorage.com](mailto:accountexecutive@anchorage.com) to follow the regular download and enrollment process.
## Notes and tips
* Marking a device as lost prevents its use for approvals. Verify the correct user before proceeding.
* Only administrators with user management permissions can initiate and approve device replacements.
* Keep approvers informed for time-sensitive recoveries so they can act on notifications quickly.
* Permission changes and device replacements require quorum approval according to your organization's policies. After quorum is met, Anchorage Digital will review for final approval. For help, contact [accountexecutive@anchorage.com](mailto:accountexecutive@anchorage.com).
# Example policy setups
Source: https://docs.anchorage.com/knowledge-base/platform/users/example-policy-setups
Configure vault policies for common goals, including trusted-destination-only withdrawals, lighter approvals on vetted transfers, and restricted vaults.
This page shows how organizations can combine policy rules with different conditions and outcomes to meet specific security goals. Each setup is built from the controls described in [Rules](/knowledge-base/platform/users/rules) — there's nothing to install or request, and no preset to apply.
Every setup below is a vault policy. The **Block** [outcome](/knowledge-base/platform/users/rules#outcomes) isn't available on the administrator policy, so organization-level operations such as user management always resolve to quorum.
Reject any withdrawal to an address that isn't a trusted destination
Keep full quorum for new destinations, reduce it for known ones
Block everything in a vault except the activity you intend
## How to read these setups
Each setup lists the rules in a policy in evaluation order. Anchorage Digital works down the list, applies the first rule that matches the operation, and resolves that rule's outcome.
A policy holds at most one conditional rule, and it always sits above the base rule for the same operation. See [Conditional rules](/knowledge-base/platform/users/policies#conditional-rules) for how the two fit together, and [Adding a conditional rule](/knowledge-base/platform/users/rules#adding-a-conditional-rule) for the steps.
## Restrict withdrawals to trusted destinations, block every other operation
Assets can only leave to an address your organization has already vetted and approved. Anything else is blocked before it reaches an approver.
| Order | Operation | Condition | Outcome |
| :---- | :------------------ | :--------------------------------- | :----------------------- |
| 1 | Withdrawal | Destination is any trusted address | Quorum, 2 of 4 approvers |
| 2 | Any vault operation | None | Block |
A withdrawal to a trusted address or to another vault on this policy matches the first rule and proceeds to quorum as normal. Every other vault operation falls through to the base rule and is blocked when you preview it.
This turns your trusted destinations into a hard control rather than a convenience. Adding a trusted destination still requires quorum approval up front under your administrator policy, so the vetting step stays intact — see [Trusted destinations](/knowledge-base/platform/users/trusted-destinations).
The outcome applies to the operation itself, not to where it started, so a withdrawal submitted through the API is rejected on the same terms as one started in the iOS app or web dashboard.
## Require fewer approvals for vetted withdrawals
A higher number of quorum approvals still applies to a withdrawal heading somewhere new (or other operations), but movement between vaults using the same policy and to trusted destinations clears with just a single approval.
| Order | Operation | Condition | Outcome |
| :---- | :------------------ | :-------------------------------------------------------------------- | :----------------------- |
| 1 | Withdrawal | Destination is any trusted address, or in any vault using this policy | Quorum, 1 of 3 approvers |
| 2 | Any vault operation | None | Quorum, 2 of 3 approvers |
Set the approval count on each rule to whatever suits your organization. The pattern is what matters: the conditional rule carries the lower threshold, and the base rule keeps your standard requirement for everything else.
The condition covers trusted destinations and vaults on the same policy together, so a single rule can't apply one threshold to internal vault transfers and a different one to trusted addresses. Both clear at the threshold you set on the conditional rule.
Sub-quorums work here too. You can require, for example, two approvals from a designated group on the base rule while the conditional rule stays at one — see [Sub-quorums](/knowledge-base/platform/users/rules#sub-quorums).
## Limit vaults to one type of activity
A set of vaults set aside for a single purpose, such as staking, where no other operation can be initiated at all.
| Order | Operation | Condition | Outcome |
| :---- | :---------------------------------------------- | :-------- | :----------------------- |
| 1 | Staking, or whichever operation you're allowing | None | Quorum, 2 of 3 approvers |
| 2 | Any vault operation | None | Block |
The default **Any vault operation** rule covers every operation rule 1 doesn't, and setting it to Block rejects them all. The rule above it re-opens the one operation the vault exists for, so staking proceeds to quorum while withdrawals, governance, and vault operations are all rejected.
Assign this policy only to the vaults you intend to restrict. A policy applies to every vault it covers, so a policy shared with an active trading vault will lock that vault down too — see [Vault policies](/knowledge-base/platform/users/vault-policies).
A default rule set to Block stops every vault operation the policy governs, including withdrawals your team may depend on. Configure the rule that allows your intended operation, and confirm it's in place, before you switch the default rule to Block.
# Gas fees and stuck transactions
Source: https://docs.anchorage.com/knowledge-base/platform/users/gas-fees-stuck-transactions
Fund network gas per wallet and resolve transactions stuck broadcasting.
On-chain sends need the network's native asset to pay gas, and a fee spike can leave a transaction stuck. This guide explains how gas funding works and what to do when a transaction won't broadcast.
## Funding gas
Every on-chain send needs the network's native gas asset in the sending wallet—ETH on Ethereum, SOL on Solana, APT on Aptos, DOT on Polkadot, and so on. Gas is **per-wallet**: there's no shared gas pool today, so each wallet that sends needs its own native balance.
To avoid topping up every wallet by hand, the gas station can fund gas automatically for supported assets. See [Gas station](/knowledge-base/platform/users/sending-assets#gas-station).
Coverage is limited to the operations in that list. Staking and unstaking outside it aren't included — an Aptos wallet, for example, needs its own APT balance before you can initiate an unstake, even with the gas station enabled. If an operation won't initiate and the wallet looks short on the native asset, fund it directly rather than waiting for an automatic top-up.
Keep a small buffer of the native gas asset in each wallet you send from, so operations aren't blocked waiting on a gas top-up.
## Transactions stuck broadcasting
The gas estimate is locked when you initiate an operation, not when it broadcasts. If network fees rise before quorum is met, the operation can stick in the **Broadcasting** status because the locked estimate no longer covers the fee.
When that happens, the platform keeps retrying the broadcast—if network fees fall back within the locked estimate, the operation completes on its own. If you'd rather not wait, cancel the operation and resubmit it so a fresh gas estimate is applied.
# Getting started
Source: https://docs.anchorage.com/knowledge-base/platform/users/getting-started
Set up the mobile app, add users, join or switch accounts, and create vaults and wallets.
Welcome to Anchorage Digital. This guide walks you through the first steps to set up your organization, from installing the mobile app to creating your first vault and wallet. Each step links to a detailed guide.
The Anchorage Digital iOS app is how you approve activity with biometric authentication, so install it first.
Administrators onboard teammates by generating an enrollment QR code and completing identity verification.
New users accept an invitation and link their device to your organization.
If you belong to more than one organization, move between them without logging out.
Vaults organize your assets and carry the policies that govern them.
Add wallets to a vault to hold specific assets and generate deposit addresses.
## Next steps
Once your vaults and wallets are set up, you're ready to move assets and manage your organization:
* [Receive assets](/knowledge-base/platform/users/receiving-assets) — Generate deposit addresses and attribute incoming deposits
* [Send assets](/knowledge-base/platform/users/sending-assets) — Initiate and approve withdrawals
* [Manage policies](/knowledge-base/platform/users/policies) — Configure administrator and vault policies for your team
* [Get an API key](/knowledge-base/platform/users/web-dashboard/developers) — Create permission groups and generate API keys to integrate your own tools
# Joining and switching accounts
Source: https://docs.anchorage.com/knowledge-base/platform/users/joining-switching
Join new accounts and switch between organizations.
If your organization has more than one account with Anchorage Digital, you may join multiple accounts and navigate between them from the iOS app.
## Joining a new account
Tap **Add user** in the iOS app, then submit biometric authentication.
Go to the **Settings** icon (bottom right), tap **Organization**, and select **Join a new organization**.
Scan the enrollment QR code provided by an administrator of the new account.
Wait for the operation to be approved. Once approved, you will gain access to the new account.
## Switching accounts
Once you have access to multiple accounts, you can navigate between them at any time.
Navigate to the **Settings** icon in the bottom right of the iOS app, then tap **Organization** to see a list of your accounts and switch between them.
# Managing users
Source: https://docs.anchorage.com/knowledge-base/platform/users/managing-users
Add, update, and remove users; change permission levels; recover access.
## Changing permission levels
Administrators with vault management permissions may adjust user permissions within a vault, and assign or remove administrator access. See [Changing permission levels](/knowledge-base/platform/users/changing-permission-levels) for step-by-step instructions.
## Removing users
Only administrators with user management permissions can remove users.
If the user is an approver on a pending operation, that operation can block their removal. Cancel or complete any pending operation that requires their approval first, then remove the user.
Tap the **gear icon** to go to **Settings**, scroll down, and tap **Team**.
Select the user you want to remove and follow the prompts.
After submitting biometric approval, the other administrators will receive a notification to approve the operation. Once quorum is met, Anchorage Digital will review for approval.
## Device replacement
If a user loses access to their device, administrators can initiate a device replacement operation.
### Replacing a lost device
When a user no longer has access to their old device:
On the new device, tap your profile in the App Store, then tap **Apps**. Search for **Anchorage Digital** and install the mobile app.
Contact [accountexecutive@anchorage.com](mailto:accountexecutive@anchorage.com) to mark your old device as lost.
After Anchorage Digital confirms the device is lost, an administrator with user management permissions goes to **Settings**, taps **Team**, then taps **Lost device** next to the user's name. Finally, tap **Set up new device**.
Once **Set up new device** is tapped, share the QR code with the user to scan.
The administrator who initiated the operation must go to **Activity**, tap the operation, and submit biometric approval.
Administrators will receive a notification to approve the operation. Once quorum is met, Anchorage Digital will review for approval.
Only administrators with user management permissions can initiate and approve the replacement operation.
### Replacing a device with access to your old device
If you still have access to your old device, see [Device and login recovery](/knowledge-base/platform/users/device-login-recovery) for the self-service steps to replace it.
## Re-installing or updating the iOS app
If you are using the same device and Apple ID that was used to initially download the app, simply update or re-download the app from the App Store. See [Updating the app](/knowledge-base/platform/users/mobile-app#updating-the-app). No device replacement process is needed.
If you're using a different Apple ID on the new device, contact [accountexecutive@anchorage.com](mailto:accountexecutive@anchorage.com) to follow the regular download and enrollment process.
For any issues with re-installation or access recovery, contact [accountexecutive@anchorage.com](mailto:accountexecutive@anchorage.com).
# Mobile app
Source: https://docs.anchorage.com/knowledge-base/platform/users/mobile-app
Download and set up the Anchorage Digital iOS app.
The Anchorage Digital iOS app is available for download on the Apple App Store. The app leverages the iPhone's advanced security features—including the Secure Enclave and biometric authentication—to provide secure, always-available access to your account.
## Downloading the app
You can download and install the Anchorage Digital application directly through Apple's App Store. Search for "Anchorage Digital," open the [Anchorage Digital App Store listing](https://apps.apple.com/us/app/anchorage-digital/id6754656781), or use the link provided by your account executive.
**Supported iOS devices:**
* iPhone: iPhone SE (2nd generation), iPhone XS, and later models
* iPad: iPad (7th generation), iPad mini (5th generation), iPad Air (3rd generation), and later models
## Migrating from the private app
Users who installed the Anchorage Digital app via a private link before March 2026 may be on the privately distributed version. Existing private apps remain fully functional and provide the same experience as the public App Store version. However, if you need to install the app on a new device, download it directly from the App Store.
If you lose access to any app or need a new install on a new device, download the app directly from Apple's App Store. To replace your device or move your user to a new phone, see [Device and login recovery](/knowledge-base/platform/users/device-login-recovery). If you still have the old device, the transfer is self-serve.
### Migration steps
Open the App Store, navigate to your account, and update the Anchorage Digital app to the latest version.
Open the updated app and go to **Settings**. Ensure your version is **2.106.0 or later**.
Download the Anchorage Digital app from the App Store.
Open the newly downloaded public app to get started.
## Deploying via Apple Business Manager (MDM)
Since the Anchorage Digital app is now public on the Apple App Store, deploying it across your organization's devices no longer requires anything from Anchorage Digital. Setting up Apple Business Manager (ABM) and your mobile device management (MDM) system is entirely self-serve on your side.
This replaces the earlier private-distribution process, which required Anchorage Digital to whitelist your organization in ABM. That process only ever applied to the [legacy private app](#downloading-the-private-app-legacy) and isn't needed for the public app.
Log into your organization's ABM account and search for "Anchorage Digital" under **Apps and Books**. Claim the number of licenses you need. The app is free, but ABM still requires claiming a license for each seat.
Once claimed, your ABM account syncs those licenses to your MDM system. This lets your IT team silently install, update, and manage the app on employee devices, with no per-device App Store interaction required.
Refer to Apple's own ABM and MDM documentation for account setup and license-assignment details specific to your MDM provider.
## Downloading the private app (legacy)
This section applies only to the legacy private app. If you're deploying the public Anchorage Digital app across your organization, see [Deploying via Apple Business Manager (MDM)](#deploying-via-apple-business-manager-mdm) above.
For users in countries where the public App Store listing was not available, the app was previously distributed via Apple Business Manager (ABM).
### App availability by region
For security reasons, the private app was distributed via the B2B app store, Apple Business Manager (ABM), rather than being publicly available.
* **If your organization has an ABM account**: Anchorage Digital can provide guidance on setting up ABM with Apple.
* **If your organization does not have an ABM account**: App redemption codes can be generated by the Anchorage Digital ABM account.
### Downloading in unsupported countries
If your organization does not have an ABM account and your Apple ID is registered outside the United States:
In the App Store, tap the **Profile Icon**, then your **Account Name**. Tap **Country/Region**, then **Change Country or Region**. Select **United States** and use Anchorage Digital's address for billing. This change can be temporary—you may switch back once the app is downloaded.
Open the download link provided by Anchorage Digital in a Safari browser to initiate the download.
Once the download is complete, go to **iPhone Settings**, tap **App Store**, and enable **Automatic Updates**.
Users with Apple IDs linked to Apple subscriptions (e.g., Apple TV) may not be able to change the region. In that case, create a new Apple ID using a different email address.
### Creating a new Apple ID (alternative)
If you cannot change your Apple ID region, create a new one:
Go to **Settings**, tap your Apple ID name and avatar, then tap **Sign Out**.
Tap **Don't have an Apple ID or forgot it?**, then **Create Apple ID**. Use an email address different from the one already in use and follow the prompts.
Check for a verification email from Apple and verify your new email address.
Tap the download link on your iPhone to initiate the download.
## Updating the app
By default, most iOS apps are configured to receive automatic updates. To manually update or force an immediate update:
Launch the App Store on your iPhone.
Tap your profile icon (avatar) in the top-right corner of the screen.
Tap **Apps** to see a list of your applications.
Scroll down to find the Anchorage Digital app. If an update is available, an **Update** button will appear next to the app name.
Tap **Update** to begin the download.
If you are updating your app in preparation for the public app release, open the Anchorage Digital app immediately after the update finishes.
## If the app won't connect or unlock
An app that hangs on the loading screen, won't unlock, or reports a connection error is usually running into a network problem rather than an account problem. Work through these checks in order:
* **Turn off VPNs and proxies** — an active VPN, proxy, or iCloud Private Relay can disrupt the app's secure connection.
* **Check for an app update** — an outdated version can cause connection and endorsement errors. See [Updating the app](#updating-the-app).
* **Force-close and reopen the app** — close it fully rather than leaving it in the background.
* **Switch networks** — try cellular data with Wi-Fi turned off, or a different Wi-Fi network. A local connectivity problem is a common cause.
* **Restart your iPhone** — a full restart, not just closing the app.
If none of these resolve it, email [accountexecutive@anchorage.com](mailto:accountexecutive@anchorage.com) with your device model and a screenshot of what you're seeing, and we'll escalate it.
If you've replaced your device or reinstalled the app and can't get back in, that's a different path — see [Device and login recovery](/knowledge-base/platform/users/device-login-recovery).
# Navigating the web dashboard
Source: https://docs.anchorage.com/knowledge-base/platform/users/navigating-web-dashboard
Log in and find your way around the Anchorage Digital web dashboard.
The Anchorage Digital web dashboard is where you manage your organization's vaults, assets, operations, and settings from a browser. Most configuration changes you make here require biometric approval through the [mobile app](/knowledge-base/platform/users/mobile-app).
## Logging in
Go to [anchorage.com](https://www.anchorage.com) and select **Log in** in the top right corner.
Open the Anchorage Digital iOS app, tap **Settings**, then **Web dashboard login**, and scan the QR code displayed on screen.
Review the requesting device's location in the iOS app and tap **Allow**.
After logging in, the dashboard shows all vaults across your accounts. You move around using the navigation on the left.
## Finding your way around
The navigation is a set of icons on the left, one for each main area. Hover over an icon to see its name.
Right-click the navigation to show or hide labels under the icons. With labels on, the area names stay visible without hovering.
Select an icon to open a panel with the pages in that area. The panel keeps the main view clean while you work.
Select an icon in the navigation. Hover over it first to confirm its name.
In the panel, select the page you need. The panel stays open so you can move between pages quickly.
Select the toggle to collapse or expand the navigation. On mobile, the menu starts collapsed.
## Dashboard
The main dashboard gives you a portfolio-level view of your holdings. From here you can:
* View account-wide and per-vault total balances — see [Reading balances](/knowledge-base/platform/users/reading-balances) for what each number means
* Open any vault to manage its wallets, deposit addresses, and holdings
* Request quotes and execute trades via the RFQ trading system — see [Trading](/knowledge-base/platform/users/trading)
For detailed instructions on creating and managing vaults and wallets, see [Vaults & wallets](/knowledge-base/platform/users/vaults-wallets).
If your organization has stablecoins enabled, the dashboard also lets you mint, redeem, and bridge stablecoins. See [Stablecoins](/knowledge-base/platform/users/stablecoins) for step-by-step instructions.
Depending on your organization's setup, the dashboard can also include **Exchanges** for external trading venues and the **Atlas network** tools **Settle**, **Collateral management**, and **Tri-party**. See [Atlas Network](/knowledge-base/platform/users/atlas-network).
## Operations
The **Operations** page is your audit trail. View, filter, and download pending and past account operations — search by transaction type, date range, or status to find specific activity.
For programmatic access to operations, see [Track operation status](/knowledge-base/platform/developers/move-money/operate/track-status) in the developer docs.
The Operations page shows activity across all vaults in your organization, not just the ones where you hold an Operator or Viewer role. Vault-level visibility gating — so users only see activity for the vaults they're assigned to — isn't available yet, but is coming soon.
If past operations won't load, refresh the page with SHIFT held down (a hard reload) to clear the stale view.
## Reporting
The **Reporting** section is where you view monthly statements and download balance and transaction reports.
* **Statements** are issued monthly and break down your holdings by asset
* **Reports** can be downloaded or scheduled for automatic delivery to recipients
See [Reporting](/knowledge-base/platform/users/web-dashboard/reporting) for details on each area.
## Tax center
The **Tax center** lets you supply cost basis information for deposits, manage tax documents like 1099-MISC forms, and certify your organization's tax information. See [Tax center](/knowledge-base/platform/users/web-dashboard/tax-center) for details.
## Developers
The **Developers** section is where you create permission groups, generate API keys, and configure webhooks. See [Get an API key](/knowledge-base/platform/users/web-dashboard/developers).
## Settings
The **Settings** section groups your organization's configuration into a few areas, plus some standalone pages.
Grouped areas:
* **Access control**: **Roles**, **Policies**, and **Team**. Manage users, roles, and approval policies. See [Policies](/knowledge-base/platform/users/policies) and [Managing users](/knowledge-base/platform/users/managing-users).
* **Billing hub**: **Invoices**. View, download, and share custody fee invoices, and manage delivery preferences.
* **Trusted addresses**: **Trusted destinations**, **Trusted sources**, and **Trusted counterparties**. See [Trusted destinations](/knowledge-base/platform/users/trusted-destinations) and [Trusted sources & deposit attribution](/knowledge-base/platform/users/trusted-sources-deposit-attribution).
Standalone pages:
* **Web3 access**: manage approved dApps and Web3 connections. See [Web3 access](/knowledge-base/platform/users/web3-access).
* **Atlas participants**: manage your organization's participants on the Atlas network. See [Atlas Network](/knowledge-base/platform/users/atlas-network).
* **Stablecoin rewards**: configure payout wallets for eligible stablecoins. See [Stablecoin rewards](/knowledge-base/platform/users/stablecoins#stablecoin-rewards).
* **Document delivery**: set up distribution lists for statements, reports, and tax documents per legal entity.
## Where features moved
If you used the previous layout, here's where to find things now.
| Previously | Now |
| :------------------------------- | :--------- |
| Vaults and wallets | Dashboard |
| Trading | Dashboard |
| Activity | Operations |
| Minting and redeeming | Dashboard |
| Statements and reports | Reporting |
| Tax center | Tax center |
| Team and policies | Settings |
| Trusted destinations and sources | Settings |
| Invoices and document delivery | Settings |
| API keys | Developers |
# On-chain interactions
Source: https://docs.anchorage.com/knowledge-base/platform/users/on-chain-interactions
Bridge assets and interact with on-chain protocols.
## STRK bridging
Bridge STRK tokens between Ethereum and Starknet using the Anchorage Digital iOS app or web dashboard.
### Before you start
Ensure the following before initiating a bridge:
* You have a wallet on the destination chain within the same organization.
* The source wallet has sufficient funds to cover gas fees:
* **Bridging from Ethereum**: The Ethereum wallet must have enough ETH to pay for gas.
* **Bridging from Starknet**: The Starknet wallet must have enough STRK\_STARKNET to pay for gas fees.
Upon first use of the bridging feature, you will be prompted to accept the Protocol Connectivity Terms of Service.
### Bridge STRK from Ethereum to Starknet
This operation converts your STRK (ERC-20) tokens on Ethereum to native STRK\_STARKNET tokens on Starknet. It involves two steps: authorizing a spender, then initiating the bridge.
#### Step 1: Authorize spender (first-time setup)
Before your first bridge, you must authorize the bridge contract as a spender. This sets a total allowance that each bridge transaction draws from.
Navigate to your vault and select the wallet holding STRK on Ethereum.
On iOS, the **Authorize spender** button is located alongside the other action buttons on the wallet screen. On web, select the **Actions** dropdown, then choose **Authorize spender**.
Enter the total amount of STRK you want to authorize for bridging. This is a cumulative limit, not a per-transaction amount.
Review and approve the operation. Once the quorum policy is met, the authorization is signed and broadcast on-chain.
You only need to authorize a spender once, as long as your remaining allowance covers the amount you want to bridge. If you exhaust your allowance or want to change it, repeat this step with a new value. To revoke authorization entirely, set the authorized amount to 0.
#### Step 2: Bridge to Starknet
Once the spender is authorized:
From the same STRK wallet on Ethereum, select **Bridge to Starknet**. On iOS, this button is located alongside the other action buttons on the wallet screen. On web, select the **Actions** dropdown, then choose **Bridge to Starknet**.
Enter the amount of STRK you'd like to bridge. This amount must be less than or equal to your remaining authorized allowance.
Review the operation details, optionally add a comment, then submit. Once the quorum policy is met, the operation is signed and broadcast on-chain.
After the transaction is confirmed on Ethereum, the bridged STRK\_STARKNET tokens are deposited into your Starknet wallet. This typically takes a few minutes to complete.
### Bridge STRK from Starknet to Ethereum
This operation converts your STRK\_STARKNET tokens on Starknet to STRK (ERC-20) tokens on Ethereum.
Navigate to your vault and select the wallet holding STRK\_STARKNET on Starknet.
Select **Bridge to Ethereum**. On iOS, this button is located alongside the other action buttons on the wallet screen. On web, select the **Actions** dropdown, then choose **Bridge to Ethereum**.
Enter the amount of STRK\_STARKNET you'd like to bridge.
Review the operation details, optionally add a comment, then submit. Once the quorum policy is met, the bridge operation is signed and broadcast on-chain.
After the transaction is initiated on Starknet, the bridged STRK (ERC-20) tokens are automatically deposited into your Ethereum wallet. This process typically takes 4–8 hours.
### Bridge summary
| | Ethereum → Starknet | Starknet → Ethereum |
| ------------------------------ | ---------------------------- | ---------------------------- |
| **Source token** | STRK (ERC-20) | STRK\_STARKNET |
| **Destination token** | STRK\_STARKNET | STRK (ERC-20) |
| **Gas token required** | ETH (on Ethereum) | STRK\_STARKNET (on Starknet) |
| **Authorize spender required** | (first-time setup) | |
| **Estimated completion time** | \~Minutes | \~4–8 hours |
| **Available on** | iOS and Web | iOS and Web |
# Onboarding your organization
Source: https://docs.anchorage.com/knowledge-base/platform/users/onboarding-organization
Onboard a new organization: KYC, enrollment QR codes, entity details, and token lockups.
This page covers what to expect when your organization first joins Anchorage Digital—from KYC through your team's first login. If you're adding a user to an organization that's already up and running, see [Adding users](/knowledge-base/platform/users/adding-users) instead.
## Onboarding sequence
For a brand-new organization, enrollment happens in this order:
Your organization's Know Your Customer (KYC) application is reviewed first. Enrollment QR codes aren't issued until KYC clears.
Each user downloads the Anchorage Digital iOS app. See [Mobile app](/knowledge-base/platform/users/mobile-app).
Your client experience team issues each user an enrollment QR code after KYC clears. Open the app, follow the prompts, and scan your code.
Each user completes their individual KYC application, including biometric setup. See [New user enrollment](/knowledge-base/platform/users/adding-users#new-user-enrollment) for the in-app steps.
QR codes come after KYC, not before. If your team hasn't received enrollment QR codes yet, KYC review is usually still in progress.
## Entity details
When completing your organization's application:
* **Match your formation documents.** The entity name must exactly match your formation documents, such as the memorandum and articles of association. Abbreviations or missing suffixes can stall the review.
* **Onboard affiliates as affiliates.** Entities affiliated with an existing client are onboarded under the affiliates section of the application, not as new clients.
## If your submission is stuck
If your application won't submit or stalls at what looks like completion, it usually means our compliance team needs more information—expect a request for information (RFI) to follow. Reach out to your client experience team if you're unsure what's holding the review.
## Token lockups and vesting
Setting up token lockups or vesting schedules is a separate process from standard custody onboarding. It follows a defined template that your client experience team provides. Once set up, allocations can be delivered into custody and claimed as they vest.
# What is Anchorage Digital?
Source: https://docs.anchorage.com/knowledge-base/platform/users/overview
Anchorage Digital institutional digital asset platform.
## Platform pillars
The ultimate combination of security and accessibility.
Obtain superior trade execution, 24/7/365 with access to multiple liquidity sources.
Safely collect rewards and participate in on-chain community governance.
Settle trades and transfers with counterparties directly from custody using Atlas — no pre-funding an exchange, no moving assets out to settle.
# Policies overview
Source: https://docs.anchorage.com/knowledge-base/platform/users/policies
Configure vault policies, manage rules, and set up quorum approvals.
Policies define the approval requirements for operations across your organization. Rules within a policy act as safety checks: when a specific action (the trigger) occurs, the rule determines the outcome — quorum approval, or an outright block.
Rules operate at two levels:
* **Admin policy** — Applies to organization-wide operations such as inviting users.
* **Vault policies** — Applies to asset-specific operations in vaults the policy is assigned to, such as withdrawing funds.
When a rule is triggered, the required administrators receive a notification to review the request. Once the necessary quorum is met, Anchorage Digital performs a final review of the operation.
To add, edit, or delete rules and configure their quorums and sub-quorums, see [Rules](/knowledge-base/platform/users/rules).
## Managing policies on iOS
You can view and edit vault policies directly from the Anchorage Digital iOS app under the vault settings.
## Conditional rules
A vault policy can hold a conditional rule in addition to its base rule. The conditional rule is evaluated first — if its condition matches the operation, its outcome applies; otherwise, the base rule applies.
A policy's conditional rule sits above its base rule. Only the topmost rule in a policy can carry a condition, so evaluation order is always conditional rule, then base rule.
The available condition checks the withdrawal destination:
* **Destination is any trusted address, or in any vault using this policy** — matches when a withdrawal goes to an address on your trusted destinations list, or to another vault covered by the same policy.
* **Quorum is** — the operation proceeds to approval once the required number of quorum members sign off.
* **Block** — the operation is rejected outright, with no quorum collected.
Whichever rule applies, its outcome is either **Quorum is** or **Block**. Block is available on vault policies only — see [Outcomes](/knowledge-base/platform/users/rules#outcomes).
A common configuration only allows withdrawals to trusted destinations: set the conditional rule's condition to destination is any trusted address with a **Quorum** outcome, and set the base rule's outcome to **Block**. See [Rules](/knowledge-base/platform/users/rules) to add a conditional rule, or [Example policy setups](/knowledge-base/platform/users/example-policy-setups) for this and other configurations in full.
# Reading balances
Source: https://docs.anchorage.com/knowledge-base/platform/users/reading-balances
Understand the dashboard total balance and the line-item balances in vault and wallet views.
The web dashboard summarizes your holdings at three levels: an account-wide total on the dashboard, a per-vault total on each vault page, and labeled line items under each asset. This page explains what each number means.
## Total balances
On the **Dashboard**, the total balance at the top of the page is the USD value of the total on-chain balance held in the account, summed across all of its vaults.
In vault views, the total balance at the top of the page is the sum of the top-line balances of the assets in that vault, as shown in the **Portfolio** tab.
## Line-item balances
Under each asset's top-line balance, the **Portfolio** and **Wallets** views break the amount into labeled line items — for example, **Available** or **Pending deposit attribution**. A line item appears only when its amount isn't zero, so different assets show different rows, and the same concept can carry a network-specific name (see the [asset-specific variants](#asset-specific-staking-variants) below).
### Standard labels
These labels can appear on any asset.
| Label | What it means |
| :------------------------------ | :-------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Available | Funds you can withdraw, transfer, or stake right now |
| Pending | An amount in transition, such as a stake being set up |
| Pending transaction | Held for a pending operation — a withdrawal, transfer, or network fee awaiting completion |
| Pending deposit attribution | A deposit held until you attribute the sender — see [Trusted sources & deposit attribution](/knowledge-base/platform/users/trusted-sources-deposit-attribution) |
| Reviewing attribution | An attributed deposit undergoing compliance screening |
| Unknown originator | A deposit whose sender couldn't be identified |
| Funds blocked | Funds blocked following compliance review |
| Deposits flagged as spam | Deposits you or Anchorage Digital flagged as spam |
| Held by \[API key name] | A hold placed programmatically by one of your API keys |
| Locked for vesting | Funds locked under a vesting or lockup schedule |
| In associated account | Funds held in an associated vesting account |
| Held for executing a settlement | Reserved for an in-flight Atlas settlement |
| Held for Atlas delegation | Reserved for Atlas delegation |
| Held for minting or burning | Reserved for a stablecoin mint or burn in progress |
### Vesting and governance labels
| Label | What it means |
| :---------------------------------------------------------------------- | :---------------------------------------------------------------------------- |
| Locked | Principal locked in the network's lock or vesting contract |
| Unlocked | Funds released from the lock and ready to use |
| Vested / Unvested | Portions of a vesting schedule that have or haven't vested yet |
| Available to be claimed | Vested funds ready to claim |
| Available to be delegated | Funds eligible for delegation |
| Rewards earned (all time) | Cumulative rewards over the life of the position |
| Delegated Voting / Electing Validator | Funds committed to governance voting or validator election |
| Locked for voting / Locked for voting delegation / Locked by vote proxy | MKR committed to Maker governance |
| Stellar network reserve | XLM reserved by the Stellar network for the wallet and its allowlisted assets |
| Unvested delegatable | Unvested funds that can still be delegated (cosmos-family vesting positions) |
These labels show the current state of a position — how much is locked, vested, or ready to claim right now. The schedule behind them, meaning the individual unlock dates and amounts, isn't shown in the web dashboard or the iOS app, and there's no export of it. If you need the full schedule for a position, raise it with your client experience team.
### Staking labels
Stakeable assets also show a staking summary with three columns that are always present: **Available to stake**, **Amount staked**, and **Unclaimed rewards**. The line items below appear as they apply.
| Label | What it means |
| :-------------------------------------- | :-------------------------------------------------------------------------------------------- |
| Staked | Principal currently delegated to a validator |
| Unbonding / Unstaking | An unstake in progress, waiting out the network's unbonding period |
| Available to be withdrawn | Unstaked funds ready to collect |
| Available to claim / Delegation Rewards | Staking rewards earned but not yet claimed |
| Available to claim (ex: BTC staking) | Unclaimed rewards attributed to a specific program — for example, Babylon BTC staking rewards |
| Restaking rewards to be claimed | Unclaimed restaking rewards |
| Redelegating | A delegation moving between validators (Cosmos-family networks) |
| Staking Reserve | A small operational reserve required by the network for staking |
### Asset-specific staking variants
Some networks name the same staking concepts differently. Labels you may see instead:
| Asset or network | Labels |
| :----------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------- |
| Ethereum (ETH) | Stake Pending; Rewards to be claimed; Restaked; Restaked in Beacon Chain; Alluvial Staking Pending / Staked / Unstaking / Unstaked / Unswept |
| Bitcoin (BTC, Babylon) | Inactive stake; Unstaking in progress |
| Solana (SOL), Fogo (FOGO) | Staking in Progress; Staked (Deactivating); Inactive Stake; Rent Reserve - Wallet; Rent Reserve - Stake Account(s) |
| Sui (SUI) | Staked Principal; Staked Rewards |
| Aptos (APT) | Unlocked stake to be withdrawn |
| Tron (TRX) | Inactive Stake – Frozen; Staked; Unstaking; Unstaked – Available to withdraw; Unclaimed rewards |
| HYPE (HyperCore) | Available - Spot account; Inactive stake - Stake account |
| Sei (SEI) | Staking in progress; Staked; Available to claim; Restaking in progress; Unstaking in progress; Staking Reserve |
| Monad (MON) | Inactive Stake |
| Stable (STABLE) | Staked |
| Starknet tokens | Unstaked; Available to claim |
| Avalanche P-Chain | Available to import |
| EigenLayer and liquid staking tokens (cbETH, LsETH, ETHx, sfrxETH) | Restaked; Restaked Delegated; Unstaked |
| Flow (FLOW) | Delegated; Delegated available and vested; Rewards; Rent Reserve - Wallet; Rent Reserve - Locked Account |
| Oasis (ROSE) | Delegated |
For how staking works and per-asset guides, see [Staking overview](/knowledge-base/platform/users/staking/overview).
# Receiving assets
Source: https://docs.anchorage.com/knowledge-base/platform/users/receiving-assets
Receive crypto deposits with deposit attribution and address poisoning protection.
## Creating a deposit address
To receive a deposit of a given asset, vault members need a deposit address for that asset. Creating a deposit address is immediate and requires neither quorum nor Anchorage Digital approval.
Go to the desired vault and tap **Deposit**, then select the asset.
Tap **Create new wallet** or tap on an existing wallet. To create a new address, tap the icon in the top right corner and follow the prompts.
Copy and share the address or QR code with the sending party.
It is also possible to create deposit addresses in the web dashboard. Members of the vault will receive a notification every time a deposit is made.
## Deposit attribution
In compliance with US federal regulations, Singapore regulations, and global anti-money laundering (AML) requirements, Anchorage Digital requires additional information related to deposit activities to fulfill "Know Your Transaction" (KYT) obligations.
If Anchorage Digital is unable to automatically attribute a pending deposit, one or more of your authorized users will be notified via email. Click **Review and attribute deposits** or use the link provided to begin attributing pending deposits in the web dashboard.
Until you attribute the originator and screening clears, an unattributed deposit appears in your total balance but isn't available to withdraw. A received or "complete" deposit isn't the same as available funds—attribution is what releases them.
Prompt action on deposit attribution requests will help avoid withdrawal delays for deposits that cannot be automatically attributed.
Anchorage Digital has built industry-first technology to automate this process and minimize inconvenience. For questions, reach out to your relationship manager or client experience manager.
## Address poisoning protection
Address poisoning is a social engineering tactic where attackers generate look-alike addresses to trick clients into sending funds to the wrong wallet.
Anchorage Digital proactively monitors incoming deposits for patterns consistent with address poisoning. When a potentially malicious deposit is detected, it is flagged in the platform so you are alerted before reusing or trusting that address elsewhere.
### Deposits from a flagged address
When a suspicious incoming deposit is detected, the address is flagged in the deposit details. You will not be able to copy the address until you review the warning and additional details about why it was flagged. This protection is available on both web and iOS.
### Withdrawals to a flagged address
If you attempt to withdraw to a flagged address, an alert appears before you can continue. Review the details carefully before deciding whether to proceed or cancel the operation. The alert also appears on the review page and remains visible in the operation details after submission.
### Trusted destinations with a flagged address
If you attempt to add a flagged address as a trusted destination, an alert appears before you can continue. Review the details carefully before deciding whether to proceed or cancel. The alert also appears on the review page and remains visible in the operation details after submission.
## Supported assets
Anchorage Digital regularly adds new digital asset support to help clients stay ahead of fast-evolving crypto markets.
To search for supported assets in the iOS app, go to **Settings**, then tap **Supported assets**. For a full list, contact your relationship manager or client experience manager.
If an asset isn't listed, you can submit a request. Tap **Make a request** on the **Supported assets** screen to submit it on platform, or contact your relationship manager or client experience manager directly. See [Requesting asset support](/knowledge-base/platform/users/asset-support-requests) for what to expect.
### Finding a token's contract address
Block explorers allow you to view and search the blockchain for transactions, addresses, tokens, and other activity.
1. Visit the explorer for the token's network:
* Aptos: [explorer.aptoslabs.com](https://explorer.aptoslabs.com/?network=mainnet)
* Arbitrum: [arbiscan.io](https://arbiscan.io/)
* Base: [basescan.org](https://basescan.org/)
* Ethereum: [etherscan.io](https://etherscan.io/)
* Optimism: [optimistic.etherscan.io](https://optimistic.etherscan.io/)
* Plume: [explorer.plumenetwork.xyz](https://explorer.plumenetwork.xyz/)
* Polygon: [polygonscan.com](https://polygonscan.com/)
* Solana: [solscan.io](https://solscan.io/)
* ZKSync: [explorer.zksync.io](https://explorer.zksync.io/)
2. Search for the token using its name or symbol.
3. The contract address will be clearly indicated on the token page.
## Stellar asset allowlisting
On the Stellar network, your wallet must first allowlist any asset other than the native currency, XLM. This is a protocol-enforced permission system required for receiving non-native assets. Assets that require allowlisting appear in the **Allowed assets** section of your wallet; assets that don't require it need no additional setup.
When you create a new Stellar wallet, Anchorage Digital automatically sponsors the required XLM reserve and allowlists every currently supported Stellar asset that requires it, so no setup is needed. You only need to allowlist manually to add newer assets to an existing wallet.
**Reserve requirements:**
* Minimum wallet balance: 1 XLM
* Each allowlisted asset increases your wallet's reserve balance by 0.5 XLM
* A nominal amount of XLM is also needed to cover transaction fees
Ensure your Stellar wallet has sufficient XLM to cover the reserve requirements before allowlisting.
Always allowlist your wallet before receiving an asset that requires it. Incoming transfers of non-allowlisted assets may fail on-chain.
### Allowlisting a Stellar asset
From the web dashboard, navigate to the desired wallet, then select the **Settings** tab. Select the **Status** toggle beside any of the supported assets to initiate the on-chain action to allowlist your wallet to receive that asset.
Removing an allowlisted asset can be done similarly, and doing so will return the 0.5 XLM reserve to your available balance.
# Rules
Source: https://docs.anchorage.com/knowledge-base/platform/users/rules
Add, edit, and delete the rules that govern policy approvals.
A rule is a safety check within a policy. When a specific operation (the trigger) occurs, the rule determines the outcome for that operation. Rules let you tailor requirements to individual operations — such as withdrawals or user management — instead of relying on the default rule alone.
A rule can also carry a condition that narrows when it applies. See [Conditional rules](/knowledge-base/platform/users/policies#conditional-rules) for how conditions and outcomes fit together.
## Outcomes
Every rule resolves to one of two outcomes. Anchorage Digital first selects the rule that matches the operation, then applies that rule's outcome.
| Outcome | Result | Approvals collected |
| :-------------------------------- | :----------------------------- | :-------------------------------------------------------------- |
| **Quorum** | Operation proceeds to approval | Yes |
| **Quorum** plus **Sub-quorum(s)** | Operation proceeds to approval | Yes, with required approvals from the **sub-quorum(s)** members |
| **Block** | Operation rejected | No |
**Quorum** sets a pool of eligible approvers, the number of approvals required, and any [sub-quorums](#sub-quorums).
**Sub-quorum** is an optional attachment to a Quorum. It allows you to select a pool of required approvers, the number of approvals required from that group, and a name. If a certain rule contains a quorum and a sub-quorum, it means that any in the quorum is eligible and may approve the operation, but the quorum formation is only complete once the sub-quorum is met.
**Block** rejects the operation instead of gating it. No quorum forms, no approver is notified, and the operation is never submitted for signing. When a rule blocks an operation, Anchorage Digital tells you which rule triggered it, so you know what to change. The action stays available in the interface, so you'll see the block when you review the operation before submitting it.
Blocked operations aren't visible to the rest of your organization (just by the user who attempts them), apart from governance operations and withdrawals initiated through the API, which will be shown as rejected under [Operations](/knowledge-base/platform/users/web-dashboard/operations).
### Where Block is available
Block is a vault policy outcome only. Rules on your [administrator policy](/knowledge-base/platform/users/administrator-policy) always resolve to quorum, so organization-level operations such as user management can't be blocked this way.
Setting a vault policy's default **Any vault operation** rule to Block rejects every operation in the vaults that policy covers. Pair it with a conditional rule above to let specific cases through — see [Adding a conditional rule](#adding-a-conditional-rule), or [Example policy setups](/knowledge-base/platform/users/example-policy-setups) for worked configurations.
A default rule set to Block stops every vault operation the policy governs, including withdrawals your team may depend on. Add the conditional rule that allows your intended operations before you switch the default rule to Block.
## Managing rules
### Adding a rule
Tap **Settings**, then **Policies**, and select the specific policy you want to edit (admin or vault).
Tap **Rules**, **Edit** to enter the policy edit mode, then select **Add rule**.
Fill in the following fields, then tap **Done**:
1. **Operation** — Select the specific operation type this rule will control (e.g., Withdraw, User management).
2. **Quorum** — Tap **Quorum is** to select the pool of users allowed to approve this operation.
3. **Approvals required** — Define the number of approvals required from that quorum pool.
4. **Sub-quorum (Optional)** — Tap **Add sub-quorum** to enforce stricter security, requiring a set number of approvals from a specific subgroup before the general quorum can be met.
Back on the Rules screen, the new rule is tagged **New**. Tap **Continue**, review your settings, and tap **Save changes**. You will be prompted to submit biometric approval — quorum approval is required.
Operations not covered by specific rules will automatically follow the default **Any vault operation** or **Any admin operation** rule.
### Adding a conditional rule
A conditional rule pairs a condition with an outcome, and is evaluated before the policy's base rule.
Tap **Settings**, then **Policies**, and select the vault policy you want to edit.
Tap **Rules**, **Edit** to enter the policy edit mode, then select **Add rule**.
Under **For**, select the operation, then select **Add condition**. Conditions are only available for **Withdrawal** rules for now.
Select the condition type **Destination**, then choose the destinations this rule applies to: **any trusted address**, **in any vault using this policy**, or both.
Under **Then**, select **Quorum is** to require approvals, or **Block** to reject matching operations outright. For Quorum, set the eligible approvers and the number of approvals required, as with any other rule, and add a sub-quorum if needed.
Tap **Continue**, review your settings, and tap **Save changes**. Follow the prompts to submit biometric approval — quorum approval is required.
**Sub-quorum** is an optional attachment to a Quorum. It allows you to select a pool of required approvers, the number of approvals required from that group, and a name. If a certain rule contains a quorum and a sub-quorum, it means that any in the quorum is eligible and may approve the operation, but the quorum formation is only complete once the sub-quorum is met.
A conditional rule must sit above the base rule for the same operation. The interface only allows adding a condition to the topmost rule, so ordering is handled for you.
### Editing a rule
Tap **Settings**, then **Policies**, and select the relevant policy.
Tap **Rules**, then tap the options menu (**...**) next to the rule you want to change and select **Edit rule**.
Update any of the following:
1. **Operation** — Change the action that triggers the rule.
2. **Outcome** — Select the outcome in case that rule is triggered.
1. **Quorum is**
1. **Required approvers (threshold)** — Change the number of approvals required.
2. **Eligible approvers (or quorum members)** — Update the base quorum members eligible to approve the request.
3. **Sub-quorums** — Add or remove sub-quorum requirements.
2. **Block** Blocks the selected operation upfront.
Tap **Continue**, review the updated rule configuration, and tap **Save changes**. Follow the prompts to submit biometric approval — quorum approval is required.
### Deleting a rule
You cannot delete the default **Any vault operation** or **Any admin operation** rules. These serve as the baseline safety net for your organization. When a custom rule is deleted, that operation type immediately reverts to following the applicable default rule.
Tap **Settings**, then **Policies**, and select the relevant policy.
Tap **Rules**, **Edit** to enter the policy edit mode, then tap the options menu (**...**) next to the rule you want to remove and select **Delete rule**.
Tap **Continue**, then **Save changes**. Follow the prompts to submit biometric approval — quorum approval is required.
## Base quorum members
The base quorum defines the pool of users — admins or operators — eligible to approve a specific operation within a policy.
### Editing base quorum members
Tap **Settings**, then **Policies**, and select the relevant policy (admin or vault).
Tap **Rules**, **Edit** to enter the policy edit mode, then tap the options menu (**...**) next to the rule you want to modify and select **Edit rule**.
Tap the **Eligible approvers** field to select or deselect approvers.
Tap **Done** to save the rule. Follow the prompts to submit biometric approval — quorum approval is required. Once quorum is met, Anchorage Digital will review the operation.
### Editing base quorum approvals
Tap **Settings**, then **Policies**, and select the relevant policy.
Tap **Rules**, then tap the options menu (**...**) next to the rule and select **Edit rule**.
Scroll down to **Number of approvals required** and select the new amount.
Tap **Done** to save the rule. Follow the prompts to submit biometric approval — quorum approval is required.
## Sub-quorums
Sub-quorums add an additional security layer to a rule. They ensure an operation cannot be completed unless a specific number of approvals are received from a designated group (e.g., "2 approvals from the Legal Team"). Multiple sub-quorums can be added to any rule.
Sub-quorum members are always selected from the base quorum, so every sub-quorum approver is also part of the base quorum.
### Adding a sub-quorum
Tap **Settings**, then **Policies**, select the relevant policy, tap **Rules**, and tap the options menu (**...**) next to the target rule and select **Edit rule**.
Scroll down and tap **Add sub-quorum**.
Enter a name and optional description for the sub-quorum. Review the details, adding more sub-quorums if needed.
Set the number of required approvals for this group and tap **Continue**. Select members from the base quorum pool and tap **Continue**.
Tap **Done** to save the rule. Follow the prompts to submit biometric approval — quorum approval is required.
### Editing sub-quorum details
Administrators can update the name or description of an existing sub-quorum.
Tap **Settings**, then **Policies**, select the relevant policy, tap **Rules**, and tap the options menu (**...**) next to the parent rule and select **Edit rule**.
Scroll down to the sub-quorum section. Tap the options menu for the sub-quorum and select **Edit details**.
Update the name or description and tap **Finish**.
Tap **Done** to save the rule. Follow the prompts to submit biometric approval — quorum approval is required.
### Editing sub-quorum members
Tap **Settings**, then **Policies**, select the relevant policy, tap **Rules**, and tap the options menu (**...**) next to the parent rule and select **Edit rule**.
Scroll down to the sub-quorum section. Tap the options menu for the sub-quorum and select **Edit approvers**.
Select or deselect members to update the pool and tap **Continue**.
Tap **Done** to save the rule. Follow the prompts to submit biometric approval — quorum approval is required.
### Editing sub-quorum approvals
Tap **Settings**, then **Policies**, select the relevant policy, tap **Rules**, and tap the options menu (**...**) next to the parent rule and select **Edit rule**.
Scroll down to the sub-quorum section. Tap the options menu for the sub-quorum and select **Edit approval limit**.
Select the new number of required approvals and tap **Save**.
Tap **Done** to save the rule. Follow the prompts to submit biometric approval — quorum approval is required.
### Deleting a sub-quorum
Tap **Settings**, then **Policies**, select the relevant policy, tap **Rules**, and tap the options menu (**...**) next to the parent rule and select **Edit rule**.
Scroll down to the sub-quorum section. Tap the options menu for the sub-quorum and select **Delete**.
Tap **Done** to save the rule. Follow the prompts to submit biometric approval — quorum approval is required.
Tap **Settings**, then **Policies**, and select the vault policy you want to edit.
Tap **Rules**, **Edit** to enter the policy edit mode, then select **Add rule**.
Select the operation, then **add condition.**
For now, conditions are only available for **Withdrawal** rules.\*\* \*\*Select the condition type **Destination.**
Now select the destinations you'd like this rule to apply to. Select **any trusted destination**, and/ or **in any vault using this policy**.
Select **Quorum** to require approvals, or **Block** to reject matching operations outright. If you choose Quorum, set the quorum pool and number of approvals required, as with any other rule, or add \*\*sub-quorum(s) \*\*if needed.
Tap **Continue**, review your settings, and tap **Save changes**. Follow the prompts to submit biometric approval — quorum approval is required.
Tap **Settings**, then **Policies**, and select the relevant policy.
Tap **Rules**, then tap the options menu (**...**) next to the rule you want to change and select **Edit rule**.
Update any of the following:
1. **Operation** — Change the action that triggers the rule.
2. **Outcome** — Select the outcome in case that rule is triggered.
1. **Quorum is**
1. \*\*Required approvers (threshold) \*\*— Change the number of approvals required.
2. **Eligible approvers (or quorum members)** — Update the base quorum members eligible to approve the request.
3. **Sub-quorums** — Add or remove sub-quorum requirements.
2. **Block** Blocks the selected operation upfront.
Tap **Continue**, review the updated rule configuration, and tap **Save changes**. Follow the prompts to submit biometric approval — quorum approval is required.
Tap **Settings**, then **Policies**, select the relevant policy, tap **Rules**, and tap the options menu (**...**) next to the target rule and select **Edit rule**.
Scroll down and tap **Add sub-quorum**.
Enter a name and optional description for the sub-quorum. Review the details, adding more sub-quorums if needed.
Set the number of required approvals for this group and tap **Continue**. Select members from the base quorum pool and tap **Continue**.
Tap **Done** to save the rule. Follow the prompts to submit biometric approval — quorum approval is required.
Tap **Settings**, then **Policies**, select the relevant policy, tap **Rules**, and tap the options menu (**...**) next to the parent rule and select **Edit rule**.
Scroll down to the sub-quorum section. Tap the options menu for the sub-quorum and select **Edit details**.
Update the name or description and tap **Finish**.
Tap **Done** to save the rule. Follow the prompts to submit biometric approval — quorum approval is required.
# Security architecture
Source: https://docs.anchorage.com/knowledge-base/platform/users/security
How Anchorage Digital secures digital assets and transaction flows.
Every product decision is informed by deep expertise in security. The result is a platform that sets the standard for digital asset security.
Anchorage Digital forgoes the use of usernames and passwords, which are susceptible to fraud, impersonation, and abuse.
Anchorage Digital does not use emails or phone numbers, so attackers cannot gain access by triggering email or SMS-based account recovery.
Only pre-approved devices may access an account.
## How it works
Anchorage Digital's transaction flow is designed to prove with certainty that a given transaction reflects an organization's intent. Once all three steps are complete, we process the transaction within minutes.
### A 3-step transaction process
Every transaction requires approval from at least two members of the organization, using authentication through authorized devices. Each user's identity is tied to a unique and unforgeable cryptographic key, created and stored in the iOS Secure Enclave.
Using automated outlier detection and human oversight, Anchorage Digital authenticates each approval based on detailed behavioral analytics. Individual and organization behavioral data—including biometrics, transaction details, and location—is examined and compared against historical patterns to detect and flag any outliers. Every transaction is independently reviewed by Anchorage Digital; no transaction moves forward without human confirmation.
Hardware Security Modules (HSMs) process the transaction only when both the organization and Anchorage Digital have approved. Private key material is generated and processed in air-gapped HSMs and is not exported outside the HSM boundary in plaintext. The system signs transactions without exposing sensitive key material. Custom logic verifies that each operation has a valid quorum of client approvals as well as Anchorage Digital approval.
## User permission levels
The platform has three user permission levels: **Administrator, Operator, and Viewer**. Users can hold multiple roles, and each vault can have its own user access configurations.
| Permission | Administrator | Operator | Viewer |
| ------------------------------- | :-----------: | :-------: | :-------: |
| Edit vault & org policies | | | |
| Add/remove users | | | |
| Create vault | | | |
| Add/remove trusted destinations | | | |
| Provision API keys | | | |
| Deposit & withdraw | | | |
| View balances | | | |
Full access to perform administrative tasks, including the ability to create and modify policies.
Access to perform operations in a vault policy, including initiating withdrawals or staking operations.
View permissions to vaults and the ability to download statements or reports.
**Organization-level vs vault-level:** Administrator is an organization-level role, granted through the administrator policy. Operator and Viewer access is assigned per vault through each vault's policy—so the same user can be an Operator in one vault and a Viewer in another.
Visibility isn't scoped by vault today, either. Any user added to the organization can see activity across all vaults in the org, regardless of whether they're an Operator on specific vaults or an Administrator at the org level. Vault-level visibility gating is coming soon.
To view roles and permissions, use the **Settings → Roles** section on the web dashboard, or check individual user details within the iOS app.
## User actions across devices
User actions are determined by the device used.
| Action | Mobile App | Web Dashboard | API | Quorum needed |
| ----------- | :--------: | :-----------: | :-------: | :-----------: |
| Deposits | | | | |
| Withdrawals | | | | |
| Trading | | | | |
| Transfers | | | | |
Biometric approval is always required on iOS, even when quorum is not. Tapping approve isn't the security step — your biometrics unlock the signing key held in the device's secure hardware, which is what actually authorizes the operation.
## How iOS and API approval differ
Both interfaces prove the same thing — that an authorized party approved the operation — but they prove it differently:
* **On iOS**, the approver is a person, in the moment. Biometrics bind the approval to a specific human on a specific enrolled device, and unlock the key in the device's secure hardware to sign.
* **Over the API**, the approver is a system — but a human quorum can still stand behind it. There's no person in the loop to scan each request, so authorization comes from a cryptographic signature: sensitive requests are signed with your Ed25519 key, and each key is scoped by [permission groups](/knowledge-base/platform/users/web-dashboard/developers).
For certain permission groups, key creation and/or permission changes require quorum approval and Anchorage Digital review. That human approval is front-loaded (when required), then reused for each signed request rather than collected again per transaction.
In both cases the operation is still subject to quorum and Anchorage Digital review where the policy requires it.
## Quorums and policies
All sensitive operations—such as withdrawing assets or changing account settings—require approval from multiple members of your Anchorage organization.
Each vault operates under a [vault policy](/knowledge-base/platform/users/vault-policies), which defines the user access configuration for that vault. A vault policy may be assigned to multiple vaults, ensuring that the same permission level and rules for operation approval are consistently applied across all of them.
Each vault must have a minimum of 3 members.
Each vault must have a minimum quorum of 2 approvers.
Set separate approval quorums for withdrawal, staking, and governance operations within the same vault policy.
**Policy customization options:**
* Customize the quorum and sub-quorums for user management, trusted destination management, and vault and API management operations
* Add or remove users from vault and account sub-policies
For more details, see [Creating a vault](/knowledge-base/platform/users/creating-vaults) and [Managing users](/knowledge-base/platform/users/managing-users).
## Why HSMs?
A **Hardware Security Module (HSM)** is a dedicated, tamper-resistant device built for one job: generating and using cryptographic keys without ever exposing them. They're the same class of hardware banks use to protect payment systems, and they're the answer to the core problem in digital asset security — a private key is just data, and data can be copied.
* **Key material stays inside secure hardware.** Private key material is generated and processed in HSMs with no direct connection to the internet. Key material is not exported outside the HSM boundary in plaintext; signing happens in protected hardware, which returns only the signature.
* **Tamper resistance is physical.** The HSMs are air-gapped and housed in protected data centers with 24/7 physical security. Attempts to physically open or probe the hardware destroy the keys rather than reveal them.
* **The approval logic runs in the hardware, not around it.** Custom logic on the HSM verifies that every operation carries a valid quorum of client approvals plus Anchorage Digital approval before it will sign. The rules can't be bypassed by compromising a server or an app, because the server and app never hold sensitive key material.
This is why losing a phone, a password, or even a server doesn't put assets at risk: there is no plaintext private key material available to steal.
# Sending assets
Source: https://docs.anchorage.com/knowledge-base/platform/users/sending-assets
Withdraw assets from vaults, use the gas station, and batch endorsements.
## Withdrawals
Withdrawals fall under the vault default policy or withdrawal policy (if configured). Both administrators and vault members included in the policy's quorum can initiate and approve withdrawals.
You may initiate withdrawals in the iOS app or the web dashboard. If initiated from the web dashboard, biometric approval must be submitted in the iOS app.
To send SOL to a program-derived (off-curve) address, such as a PDA, it must first be added as a trusted destination. Self-service whitelisting for these addresses isn't available yet — contact your client experience team to add one on your behalf.
### Withdrawing from iOS
Go to the desired vault and tap **Withdraw**.
Search for and tap the asset you would like to withdraw, then select the wallet from which you would like to withdraw.
Enter the withdrawal amount, enable the gas station if applicable, and tap **Continue**. Enter the destination address and follow the prompts.
Reply to any questions or confirm the destination details. Add a comment (optional) and follow the prompts to submit biometric approval.
### Withdrawing from the web dashboard
Go to the desired vault and click **Withdraw** in the top-right corner.
Select the asset and wallet from which you would like to withdraw. Enter the amount, and enable the gas station if applicable.
Enter the destination address to which you would like to send the funds.
Review and confirm the information, then submit. Go to the iOS app to endorse the withdrawal with biometric approval.
### Quorum approvals
Members of the default vault policy or the withdrawal policy (if applicable) will receive a notification to approve the withdrawal. Once the required quorum and sub-quorum approvals are submitted, Anchorage Digital will review the withdrawal for approval.
If the withdrawal matches a rule with a **Block** [outcome](/knowledge-base/platform/users/rules#outcomes), it's rejected when you review it and no approval is collected.
## Withdrawing tagged assets
Some assets require a destination tag or memo alongside the address—XRP is the most common example. The tag identifies the recipient at the destination, so the funds must arrive with the correct tag attached.
Withdraw tagged assets only to a saved [trusted destination](/knowledge-base/platform/users/web-dashboard/trusted-destinations) that carries the correct tag. A one-time address entered at withdrawal can drop the tag; a trusted destination stores the tag with the address, so every withdrawal includes it.
A wrong or missing tag can misroute funds, and misrouted tagged-asset withdrawals are hard to reverse. Confirm the tag with the recipient before adding the trusted destination.
## Gas station
Most blockchains charge a network fee — "gas" — paid in the network's native asset (ETH on Ethereum, SOL on Solana). To move an ERC-20 token, for example, the wallet sending it also needs ETH on hand to pay the fee. That creates an operational chore: you'd have to keep every wallet topped up with the right native asset just in case you want to transact.
The Anchorage Digital gas station removes that chore by automating gas top-ups, so wallets have the native asset needed to pay network fees without manual funding and rebalancing.
The gas station is available for:
* ETH withdrawals and transfers
* ERC-20 withdrawals and transfers
* SOL withdrawals and transfers
* ETH staking
The gas station is enabled at the organization level. Once a withdrawal or transfer is approved, the gas station—an address controlled by Anchorage Digital—deposits the estimated network fee into your wallet to cover gas for that transaction. Any unused funds remain in your wallet.
If you don't see the gas station toggle for a transaction and would like to activate it, contact your client experience manager.
### Using the gas station
When initiating a withdrawal from iOS or the web dashboard, toggle on the **gas station** option after entering the withdrawal amount. Continue following the prompts to submit the withdrawal for quorum approval.
## Batched endorsements
Multiple operations can be approved simultaneously in the Anchorage Digital iOS app, allowing for secure and efficient approval of your operations. This feature helps streamline your workflow by letting you manage several pending activities at once.
Go to **Pending activity** (bell icon) to see the list of operations awaiting approval.
Tap **Select** in the top right corner. Select the operations you wish to approve and tap **Confirm and review**.
Review each operation's details and select **Approve**, **Reject**, or **Review later** as appropriate.
Once finished, review the selection for each operation and follow the prompts to submit biometric approval.
Batched endorsements are processed once the required quorum is met.
# Atlas collateral management
Source: https://docs.anchorage.com/knowledge-base/platform/users/settlement-workflows-collateral-management
Reference guide for Anchorage Digital's Atlas collateral management service, including key concepts, transaction lifecycle, operations management, and notifications.
Anchorage Digital's Atlas collateral management is an agency service for institutional lenders and borrowers engaged in crypto-secured transactions. The service mitigates counterparty risk and reduces operational overhead by combining regulated custody with automated risk monitoring.
Typically, Anchorage Innovations LLC acts as the collateral manager (agent), while Anchorage Digital Bank, N.A. (an OCC-chartered federal trust bank) or Anchorage Digital Singapore Pte. Ltd. (licensed by MAS) acts as the Custodian.
***
## Communications
**Approved channels**
All communications in connection with Collateral management services are made over email:
* **General communication:** [admin-collateralmanagement@anchorage.com](mailto:admin-collateralmanagement@anchorage.com)
* **Notices, urgent items, or operations submissions:** [collateralmanagement@anchorage.com](mailto:collateralmanagement@anchorage.com)
**Collateral management team**
The Anchorage Digital Collateral Management team is responsible for monitoring transaction health, issuing margin calls and other notices, initiating transfers of collateral assets, and providing reporting.
***
## Key terminology
### Participants
* **Pledgor:** The borrower or counterparty who provides digital assets as collateral to secure an obligation.
* **Secured party:** The institution or lender who provides credit and receives collateral from a Pledgor.
* **Collateral manager:** Third-party role fulfilled by Anchorage Digital, combining the Custodian (holding assets) and the collateral manager (monitoring risk).
### Transaction components
* **Exposure:** The outstanding transaction or obligation being secured, such as a loan or repo.
* **Collateral package:** The collection of assets pledged by a Pledgor to secure an Exposure. This is the primary object for monitoring.
* **Risk metrics (LTV):** The critical metric measuring the ratio of the Exposure to the weighted value of the collateral. The system calculates LTV in near real-time.
### States
The current condition of a collateral package, determined by its LTV against predefined thresholds.
* **Healthy:** Collateral levels do not require action — LTV falls between the margin return and margin call thresholds.
* **Margin return:** Pledgor is eligible for a return of collateral. Action taken upon entering this state: None or Sweep.
* **Margin call:** Pledgor is required to top up collateral within the defined cure period to bring the LTV back to the return-to-LTV level. If the cure period expires before a valid top-up is received, action taken: None, Full, Partial, or Sweep.
* **Critical:** Unless cure period protection is configured and the cure period has not expired, the system immediately takes action: None, Full Liquidation, Partial Liquidation, or Sweep.
### Actions
A pre-configured, automated response the system executes when a Collateral Package enters a specific state.
* **None:** Notify both parties.
* **Full liquidation:** Full liquidation of collateral and repayment of the loan, reducing both Exposure and collateral value to zero.
* **Partial liquidation:** Partial liquidation of collateral and partial repayment of the loan in the amount that brings the LTV back to a healthy state.
* **Sweep:** Move the entire collateral balance to the Secured Party, reducing both Exposure and collateral value to zero.
### Concepts and inputs
* **Cure period:** A configurable grace period (in hours) following a margin call, during which a Pledgor can deposit additional collateral to resolve a shortfall before a default action is taken.
* **Return-to-LTV:** A specific LTV target a collateral package must reach to return to a healthy state after a non-healthy state change. If the price of an asset changes during transit, the quantity sent may be insufficient to cure the state by the time it is received.
* **Warning level:** Each LTV threshold can have a warning level configured inside the relevant threshold. Upon breach, Anchorage Digital notifies both parties that the threshold is approaching.
* **Operation:** A record in the system's transaction log indicating a change in a collateral balance (e.g., `TOP_UP`) or an Exposure balance (e.g., `PAY_DOWN`).
***
## Transaction lifecycle
1. **Setup & configuration:** The secured party and pledgor execute bilateral transaction agreements and provide transaction details and risk parameters to Anchorage Digital, including LTV thresholds, eligible assets, cure periods, and predefined actions.
2. **Funding:** The pledgor deposits the required collateral into their segregated vault/wallet at the designated Anchorage Digital custodian. The secured party funds the loan/exposure and notifies the Anchorage Digital collateral management team.
3. **Monitoring:** The system begins 24/7 automated monitoring, calculating LTV in near real-time.
4. **Threshold events:** If the LTV breaches a configured threshold, the system automatically takes the predefined action — warning notification, margin call, critical liquidation, or margin return.
5. **Resolution & reporting:** If a margin call occurs, the pledgor submits a `TOP_UP` operation to deposit additional collateral and satisfy the return-to-LTV requirement. If the margin call is not cured or a critical threshold is breached, Anchorage Digital coordinates collateral liquidation via its trading desks. Participants have continuous access to package status via API and dashboard.
***
## Asset pricing for valuation
The Atlas collateral management system uses four primary parameters to determine real-time asset valuation within a collateral package. These settings define the data pipeline and logic used to calculate the LTV ratio.
If the price source becomes unavailable or Anchorage Digital reasonably determines that prices are unreliable due to low or inconsistent trading volumes or other factors, Anchorage Digital may use an alternative source at its reasonable sole discretion.
**Price source provider**
The upstream data aggregator or oracle used to fetch market data. Amberdata is used for centralized exchange (CEX) market data aggregation; Chainlink is used for decentralized, on-chain price feeds.
**Price cource**
The exact venue or data feed queried from the selected provider. Most major exchanges are supported.
**Back-up pricing**
If a primary price source becomes unavailable or diverges from the prevailing market price, the system automatically transitions to a backup feed from a reputable commercial provider.
**Pricing type**
The specific metric extracted from the price source's order book or trade history to establish the asset's current system value: **Bid** (highest outstanding buy order), **Ask** (lowest outstanding sell order), **Mid** (median between Bid and Ask), **Last** (price of the most recently matched trade), or **Default** (used for Chainlink and index data feeds).
**Asset weight**
A numerical parameter that applies a risk discount (haircut) to the calculated market value of an asset before it is aggregated into the total collateral package value. Configurable from 0% to 100%. For example, if an asset's spot price is $1,000 and the weight is configured to 80%, the system recognizes $800 of value per unit for LTV calculations.
***
## Operations management
Operations modify the balances of the collateral package and/or the exposure. Anchorage Digital automatically books operations it is aware of, such as additional collateral deposits and collateral returns.
For operations Anchorage Digital may not be aware of — such as a lender sending fiat loan principal to the borrower through traditional rails — the appropriate party must notify Anchorage Digital via API or an authorized email address.
### Collateral operations
| Operation | Effect | Description |
| :------------------------- | :--------------------------- | :-------------------------------------------------------------------------------------------------- |
| `INITIAL_DEPOSIT` | Increases collateral balance | First collateral deposit. |
| `TOP_UP` | Increases collateral balance | Adds collateral, often in response to a margin call. |
| `MARGIN_RETURN` | Decreases collateral balance | Excess collateral returned to the Pledgor. |
| `CLOSE_RETURN` | Reduces collateral to zero | Full collateral return at the conclusion of a lending arrangement. |
| `REHYPE_OUT` / `REHYPE_IN` | Logs rehypothecation | Records when collateral has been rehypothecated out of or returned to its original custody account. |
| `GAS_FEE` | Records on-chain costs | Captures costs for on-chain withdrawal or deposit related to collateral operations. |
### Exposure operations
| Operation | Effect | Description |
| :----------------- | :------------------------- | :-------------------------------------------------------------------------------- |
| `INITIAL_FUNDING` | Increases exposure | Initial loan amount. |
| `PAY_UP` | Increases exposure | Upsize in the loan. |
| `PAY_DOWN` | Decreases exposure | Partial loan repayment. |
| `INTEREST_ACCRUAL` | Increases exposure | Accounts for accrued interest. |
| `INTEREST_PAYDOWN` | Decreases exposure | Accrued interest payment. |
| `CLOSE` | Decreases exposure to zero | Full repayment. |
| `GAS_FEE` | Records on-chain costs | Captures costs for on-chain withdrawal or deposit related to exposure operations. |
### Liquidation operations (system-generated)
| Operation | Description |
| :-------------------- | :--------------------------------------------------------------------------------------------- |
| `FULL_LIQUIDATION` | Reduces both exposure and collateral to zero after a complete sale of collateral. |
| `PARTIAL_LIQUIDATION` | Reduces exposure and collateral by the amount needed to bring the LTV back to a healthy state. |
| `SWEEP` | Transfers the entire collateral balance to the secured party, reducing both balances to zero. |
***
## Liquidations monitoring & management
Anchorage Digital provides liquidation capabilities through the Atlas platform, designed to protect the secured party's interests through real-time monitoring and rapid execution.
**Monitoring and triggering**
The platform features 24/7 monitoring with real-time price updates for all collateralized assets. Alerts for warnings, margin calls, returns, and critical states are sent in real-time via email and API to both parties and the Anchorage Digital team. Redundant SMS, voice, and email alerts ensure immediate awareness and execution.
**Order management and liquidity**
Multiple liquidation orders are handled on a first-in, first-out (FIFO) basis, determined by the exact timestamp the liquidation was triggered. Anchorage Digital aggregates liquidity from major market makers and trades against the best available price unless otherwise agreed.
***
## Participant email configuration
Three distinct email lists are configured per participant to direct communications to the appropriate stakeholders.
| Email list | Field | Purpose |
| :------------ | :--------------------- | :-------------------------------------------------------------------------------------------------------------------------------------- |
| Notification | `notice_emails` | High-priority, time-sensitive alerts and formal notices — including margin calls, cure period expirations, and default notices. |
| Reporting | `reporting_emails` | Standard periodic reporting, such as daily or monthly collateral valuation summaries. |
| Configuration | `configuration_emails` | Authorized addresses permitted to provide ad-hoc instructions or submit CSV files to update thresholds, assets, or participant details. |
***
## Email and webhook notifications
The collateral management system sends email notices to the secured party and pledgor for specific events, subject to internal logic that prevents alert fatigue.
* **Warning levels:** Warning LTV thresholds can be configured inside the margin call and critical state thresholds. Warnings are sent at most once every 24 hours.
* **State transitions:** An email is sent immediately upon transition to healthy, margin return, margin call, or critical state. These emails include current LTV, thresholds, return-to-LTV targets, suggested action amounts, and cure period deadlines.
* **Cure period expiry:** A notification is sent upon cure period expiry detailing the impending action (full liquidation, partial liquidation, or sweep).
* **Webhooks:** Webhook notifications can be configured for state transitions, providing the same real-time information and metadata as email notifications.
# Stablecoins
Source: https://docs.anchorage.com/knowledge-base/platform/users/stablecoins
Mint, redeem, bridge stablecoins, and earn stablecoin rewards.
A **stablecoin** is a digital asset designed to hold a fixed value — typically pegged 1:1 to a fiat currency like the US dollar. Because the value doesn't fluctuate with the broader crypto market, stablecoins are useful for moving value on-chain quickly, settling trades without converting back to fiat, and holding liquidity in a form that can earn rewards or be deployed into DeFi protocols.
Anchorage Digital uses a single Convert flow for minting, redeeming, and bridging stablecoins. All operations require iOS app authentication for authorization.
## Supported assets
Anchorage supports mint and redeem of the following assets using the Convert modal:
* USDtb
* USDGO
* USDPT
* fUSD
Any stablecoin not listed above is not supported via the Convert modal.
USAT is the exception. Minting and burning USAT aren't available through Convert — these operations require separate onboarding to Hadron, a third-party interface. Contact your Relationship Manager to begin Hadron onboarding.
## Contract addresses
Use the addresses below to confirm you're interacting with the official on-chain contract for each stablecoin before sending or receiving funds. Always cross-check against the block explorer link and the issuer's own documentation — never rely on an address from an unverified source.
| Stablecoin | Address | Explorer link |
| ---------------------- | ---------------------------------------------- | ------------------------------------------------------------------------------------------ |
| USDtb (Ethereum) | `0xC139190F447e929f090Edeb554D95AbB8b18aC1C` | [View on Etherscan](https://etherscan.io/token/0xC139190F447e929f090Edeb554D95AbB8b18aC1C) |
| USDtb (Solana) | `8yXrtJ54jZtE84xEBzTESKuegjcAkAuDrdAhRd8i8n3T` | [View on Solscan](https://solscan.io/token/8yXrtJ54jZtE84xEBzTESKuegjcAkAuDrdAhRd8i8n3T) |
| USDPT (Solana) | `HVWf8JmLoHs99Lw8Psf3fyqAtA4crWxCPkrmSdNjhNH3` | [View on Solscan](https://solscan.io/token/HVWf8JmLoHs99Lw8Psf3fyqAtA4crWxCPkrmSdNjhNH3) |
| USAT (Ethereum) | `0x07041776f5007ACa2A54844F50503a18A72A8b68` | [View on Etherscan](https://etherscan.io/token/0x07041776f5007ACa2A54844F50503a18A72A8b68) |
| USAT (Celo) | `0xD2ab3C9A02DBBAB236BfEC45D1d755DF4267F771` | [View on CeloScan](https://celoscan.io/token/0xD2ab3C9A02DBBAB236BfEC45D1d755DF4267F771) |
| USDGO (Solana) | `72puLt71H93Z9CzHuBRTwFpL4TG3WZUhnoCC7p8gxigu` | [View on Solscan](https://solscan.io/token/72puLt71H93Z9CzHuBRTwFpL4TG3WZUhnoCC7p8gxigu) |
| fUSD (Ethereum) | `0x1676b80EDD36B18a3C3432c11Ed25D37FdE9c92A` | [View on Etherscan](https://etherscan.io/token/0x1676b80EDD36B18a3C3432c11Ed25D37FdE9c92A) |
| fUSD (BNB Smart Chain) | `0x1676b80edd36b18a3c3432c11ed25d37fde9c92a` | [View on BscScan](https://bscscan.com/token/0x1676b80edd36b18a3c3432c11ed25d37fde9c92a) |
| ZLUSD (Solana) | `7NNkMtGACBbwJdMRYD2KchTKm2xBwnsb4bT7YSfRUWZ4` | [View on Solscan](https://solscan.io/token/7NNkMtGACBbwJdMRYD2KchTKm2xBwnsb4bT7YSfRUWZ4) |
## Mint stablecoins
Mint new stablecoins from your USD balance and deposit them directly into a wallet. Each mint converts USD to stablecoins at a 1:1 ratio.
### Before you start
* Confirm you have an available USD balance in the source account.
* Confirm your policy permissions allow you to initiate conversions.
* Have the Anchorage Digital iOS app available — you'll need it to authorize the operation.
### Where to start
You can mint stablecoins from two places in the web dashboard:
For managing stablecoin operations across vaults. In the **Dashboard**, select **Stablecoins**, then select **Convert**.
For minting directly into a specific vault you're already working in. Go to your vault and select **Convert** in the top-right corner.
Both paths use the same conversion form once you reach it.
### Complete the conversion
1. In the conversion dialog, US Dollars is pre-selected in the **From** field.
2. Select the **To** asset dropdown labeled **Select asset**.
3. Choose the stablecoin you want to mint (for example, USDGO on Solana, USDPT on Solana, or USDtb on Mainnet).
Choose the wallet where the newly minted stablecoins will be deposited. The available balance for each wallet appears next to its name.
1. In the **From** field, enter the amount of USD you want to convert.
2. The **To** field automatically populates with the equivalent stablecoin amount at a 1:1 ratio.
3. Review the summary at the bottom (for example, "Send \$100 to issue 100 USDGO on Solana").
1. Select **Preview conversion**.
2. Review the operation summary. Confirm the asset, amount, source wallet, and destination wallet are correct.
3. Select **Confirm and submit for conversion**.
### Approval and settlement
Anchorage Digital prompts you to authorize the conversion in the iOS app.
1. Open the app on your mobile device.
2. Confirm with biometric authentication.
If your policy requires multiple approvals, the operation status stays **Initiated** until the required quorum members have approved the request. You can track progress in the **Transactions** tab of the Stablecoins dashboard or on the **Operations** page in the main navigation.
Once the quorum is met:
* Anchorage Digital reviews the operation.
* Our Hardware Security Module (HSM) signs the operation.
* Anchorage Digital issues the stablecoins on-chain.
Open the **Portfolio** tab of the Stablecoins dashboard or your vault to see the updated balance. The new stablecoins appear in the destination wallet.
***
## Redeem stablecoins for USD
Redeem stablecoins for USD directly on the platform. Each redemption burns the stablecoins from your wallet and credits the equivalent USD to your [USD wallet](/knowledge-base/platform/users/usd-banking) at a 1:1 ratio.
### Before you start
* Confirm the wallet you want to redeem from holds the stablecoins.
* Confirm your policy permissions allow you to initiate conversions.
* Have the Anchorage Digital iOS app available — you'll need it to authorize the operation.
### Where to start
You can redeem stablecoins from two places in the web dashboard:
For managing stablecoin operations across vaults. In the **Dashboard**, select **Stablecoins**, then select **Convert**. Choose the account and vault that holds the stablecoins, then select the swap arrow between the **From** and **To** fields to reverse the direction so the stablecoin is the **From** asset and USD is the **To** asset.
For redeeming directly from a specific vault. Go to your vault and select **Convert**. Select the **From** asset dropdown and choose the stablecoin you want to redeem — the **To** field automatically switches to US Dollars.
Both paths use the same conversion form once you reach it.
### Complete the redemption
1. From the **From** asset dropdown labeled **Select asset**, choose the stablecoin you want to redeem (for example, USDGO on Solana).
2. Select the source wallet that holds the stablecoins. The available balance for each wallet appears next to its name.
1. In the **From** field, enter the amount of stablecoins you want to redeem.
2. The **To** field automatically populates with the equivalent USD amount at a 1:1 ratio.
3. Review the summary at the bottom (for example, "Redeem 100 USDGO on Solana to receive \$100").
1. Select **Preview conversion**.
2. Review the operation summary. Confirm the stablecoin, amount, and wallet details are correct.
3. Select **Confirm and submit for conversion**.
### Approval and settlement
Anchorage Digital prompts you to authorize the conversion in the iOS app.
1. Open the app on your mobile device.
2. Confirm with biometric authentication.
If your policy requires multiple approvals, the operation status stays **Initiated** until the required quorum members have approved the request. You can track progress in the **Transactions** tab of the Stablecoins dashboard or on the **Operations** page in the main navigation.
Once the quorum is met:
* Anchorage Digital reviews the operation.
* Our Hardware Security Module (HSM) signs the operation.
* Anchorage Digital burns the stablecoins and credits the USD to your USD wallet.
Open the **Portfolio** tab of the Stablecoins dashboard or your vault to see the updated USD balance.
***
## Bridge stablecoins
Bridge stablecoins across blockchains directly on the platform. Each bridge converts a stablecoin on one network to the same stablecoin on another network (for example, USDtb on Ethereum Mainnet to USDtb on Solana) at a 1:1 ratio.
### Before you start
* Confirm the wallet you want to bridge from holds the stablecoins.
* Confirm both the source stablecoin and the destination network are supported for bridging.
* Confirm your policy permissions allow you to initiate conversions.
* Have the Anchorage Digital iOS app available — you'll need it to authorize the operation.
### Where to start
You can bridge stablecoins from two places in the web dashboard:
For managing stablecoin operations across vaults. In the **Dashboard**, select **Stablecoins**, then select **Convert** and choose the account and vault that holds the stablecoins.
For bridging directly from a specific vault. Go to your vault and select **Convert**.
Both paths use the same conversion form once you reach it.
### Complete the bridge
1. Select the **From** asset dropdown.
2. Choose the stablecoin you want to bridge from (for example, USDtb on Mainnet).
Only supported stablecoins appear in the list.
3. Select the source wallet on the origin chain. The available balance for each wallet appears next to its name.
1. Select the **To** asset dropdown labeled **Select asset**.
2. Choose the same stablecoin on the destination chain (for example, USDtb on Solana).
3. Select the destination wallet on the target chain.
1. In the **From** field, enter the amount of stablecoins you want to bridge.
2. The **To** field automatically populates with the equivalent amount at a 1:1 ratio.
3. Review the summary at the bottom (for example, "Bridge 10 USDtb on Mainnet to 10 USDtb on Solana").
1. Select **Preview conversion**.
2. Review the operation summary. Confirm the source asset, destination asset, amounts, and wallet details are correct.
3. Select **Confirm and submit for conversion**.
### Approval and settlement
Anchorage Digital prompts you to authorize the conversion in the iOS app.
1. Open the app on your mobile device.
2. Confirm with biometric authentication.
If your policy requires multiple approvals, the operation status stays **Initiated** until the required quorum members have approved the request.
Once the quorum is met:
* Anchorage Digital reviews the operation.
* Our Hardware Security Module (HSM) signs the operation.
* The stablecoins are burned on the source chain and minted on the destination chain.
Return to your vault dashboard to view the updated balances across your wallets.
***
## Stablecoin rewards
Stablecoin rewards let your organization earn an ongoing return for holding eligible stablecoins in custody.
**How it works:** you enroll, configure a payout wallet for each eligible asset, and Anchorage Digital calculates rewards daily based on your eligible balance. Rewards are paid to the wallet you choose.
Rates are either tied to a published reference rate (e.g., the Effective Federal Funds Rate) or set as a standalone rate. Separately, rates are either tiered by balance or flat.
For assets with a tiered structure, rewards are tiered by the total eligible digital asset balance (USD value), so larger balances earn a higher rate — for these, each tier's Annual Rewards Rate (ARR) is expressed as the reference rate minus a spread. Assets without a tiered structure apply a single published rate to the full eligible balance, regardless of size.
Whether a given asset is tied to a reference rate, tiered, or both is specified under that asset.
Your assets remain accessible at any time: no lending, no rehypothecation, and no lockups.
**Eligible stablecoins:** USDGO, USDtb, USDG, PYUSD, USDe
Organizations with legal entities in Canada or the EU are not eligible for the stablecoin rewards program.
Enrollment must be completed by an admin of your organization. You can enroll even if you don't currently hold eligible stablecoins — you'll start earning rewards once you deposit eligible stablecoins and your payout wallets are configured.
### Where to start
You can enroll in stablecoin rewards from the Stablecoins dashboard. In the **Dashboard**, select **Stablecoins**, then go to the **Portfolio** tab. If your organization isn't enrolled, select **Enroll now** next to **Rewards status** to begin.
### Configure your payout wallets
Once enrolled, the **Rewards status** field on the Portfolio tab shows **Enrolled**, with a **Configure** button in its place. Select **Configure** to set the vault and wallet that will receive rewards for each eligible asset.
If your accounts don't appear immediately, refresh your browser.
For each eligible asset, choose the vault and wallet where you want to receive rewards. If you don't have an existing wallet for an asset, follow the deposit address instructions to create one first.
Select **Save**. The **Rewards status** field on the Portfolio tab shows whether all assets are configured.
### Update your configuration
You can change the vault and wallet that receive rewards at any time. Updates must be made by an admin.
On the Stablecoins dashboard's **Portfolio** tab, select **Configure** next to **Rewards status**.
Select the new vault and wallet for the asset, then select **Save**.
### Rewards rates
Each row in the tables below shows the Annual Rewards Rate that applied for that specific month only. A month's rate does not carry over or apply to any other month — each one is set independently based on that month's benchmark.
#### Anchorage Digital issued stablecoins
**USDGO**
Minimum eligible digital asset balance: \$0
Reference rate: [Effective Federal Funds Rate (EFFR)](https://www.newyorkfed.org/markets/reference-rates/effr) as published by the Federal Reserve Bank of New York
| Month | USDGO Annual Rewards Rate |
| -------------- | ------------------------- |
| September 2026 | TBD |
| August 2026 | 2.34% |
**USDtb**
Minimum eligible digital asset balance: \$0
Rates are updated on the 10th of the following month. For example, November's rates are updated by December 10.
| Month | USDtb Annual Rewards Rate |
| -------------- | ------------------------- |
| September 2026 | TBD |
| August 2026 | 3.23% |
| July 2026 | 3.23% |
| June 2026 | 3.23% |
| May 2026 | 3.23% |
| April 2026 | 3.23% |
| March 2026 | 3.18% |
| February 2026 | 3.27% |
| January 2026 | 3.33% |
| December 2025 | 3.45% |
| November 2025 | 3.65% |
#### Non-Anchorage-issued stablecoins
**USDG**
Minimum eligible digital asset balance: \$0
Reference rate: [Effective Federal Funds Rate (EFFR)](https://www.newyorkfed.org/markets/reference-rates/effr) as published by the Federal Reserve Bank of New York
Tiers are based on eligible balance held with custody/wallet service provider. Rates use EFFR as the base rate, with a spread applied per tier. The rate shown for each month is the **net rate** — EFFR minus that spread, averaged over the month — and reflects the final annual rate you could have earned holding that balance for the full month.
Actual daily rewards are calculated using that day's EFFR, not the monthly average.
| Month | \<\$1M | \$1M–\$2M | \$2M–\$5M | \$5M–\$10M | ≥\$10M |
| -------- | ------ | --------- | --------- | ---------- | ------ |
| Sep 2026 | TBD | TBD | TBD | TBD | TBD |
| Aug 2026 | 1.80% | 2.00% | 2.20% | 2.30% | 2.40% |
| Jul 2026 | 1.80% | 2.00% | 2.20% | 2.30% | 2.40% |
| Jun 2026 | 1.80% | 2.00% | 2.20% | 2.30% | 2.40% |
| May 2026 | 1.80% | 2.00% | 2.20% | 2.30% | 2.40% |
| Apr 2026 | 1.81% | 2.01% | 2.21% | 2.31% | 2.41% |
| Mar 2026 | 1.81% | 2.01% | 2.21% | 2.31% | 2.41% |
| Feb 2026 | 1.81% | 2.01% | 2.21% | 2.31% | 2.41% |
| Jan 2026 | 1.81% | 2.01% | 2.21% | 2.31% | 2.41% |
**PYUSD**
Minimum eligible digital asset balance: \$0
Reference rate: [Effective Federal Funds Rate (EFFR)](https://www.newyorkfed.org/markets/reference-rates/effr) as published by the Federal Reserve Bank of New York
Tiers are based on eligible balance held with custody/wallet service provider. Rates use EFFR as the base rate, with a spread applied per tier. The rate shown for each month is the **net rate** — EFFR minus that spread, averaged over the month — and reflects the final annual rate you could have earned holding that balance for the full month.
Actual daily rewards are calculated using that day's EFFR, not the monthly average.
| Month | \<\$1M | \$1M–\$2M | \$2M–\$5M | \$5M–\$10M | ≥\$10M |
| -------- | ------ | --------- | --------- | ---------- | ------ |
| Sep 2026 | TBD | TBD | TBD | TBD | TBD |
| Aug 2026 | 2.30% | 2.80% | 3.00% | 3.20% | 3.30% |
| Jul 2026 | 2.30% | 2.80% | 3.00% | 3.20% | 3.30% |
| Jun 2026 | 2.30% | 2.80% | 3.00% | 3.20% | 3.30% |
| May 2026 | 2.30% | 2.80% | 3.00% | 3.20% | 3.30% |
| Apr 2026 | 2.31% | 2.81% | 3.01% | 3.21% | 3.31% |
| Mar 2026 | 2.31% | 2.81% | 3.01% | 3.21% | 3.31% |
| Feb 2026 | 2.31% | 2.81% | 3.01% | 3.21% | 3.31% |
| Jan 2026 | 2.31% | 2.81% | 3.01% | 3.21% | 3.31% |
**USDe**
Minimum eligible digital asset balance: \$0
Rates are updated on the 10th of the following month. For example, November's rates are updated by December 10.
| Month | USDe Annual Rewards Rate |
| -------------- | ------------------------ |
| September 2026 | TBD |
| August 2026 | 3.20% |
| July 2026 | 3.10% |
| June 2026 | 3.07% |
| May 2026 | 2.95% |
| April 2026 | 2.88% |
| March 2026 | 2.80% |
| February 2026 | 2.88% |
| January 2026 | 3.78% |
| December 2025 | 3.52% |
| November 2025 | 3.20% |
### General program methodology
**Rewards model**
Rates are either tied to a published reference rate or set as a standalone rate, and separately, either tiered by balance or flat. For assets with a tiered structure, rewards are tiered by the total eligible digital asset balance (USD value), so larger balances earn a higher rate — each tier's Annual Rewards Rate (ARR) is expressed as the reference rate minus a spread. Assets without a tiered structure apply a single published rate to the full eligible balance, regardless of size. Whether a given asset is tied to a reference rate, tiered, or both is specified under that asset.
**Balance and reward calculation**
Balance calculation: Eligible digital asset balances are calculated in U.S. Dollars by applying closing prices, as provided by CryptoCompare.com at the close of each day (UTC), or if unavailable, other reliable, reputable third-party pricing sources, selected at Program Administrator's sole discretion.
Reward calculation: Rewards are calculated daily based on the following formula:
```text theme={null}
Eligible digital asset balance × (Annual Rewards Rate ÷ 365)
```
### Program terms and risks
The stablecoin rewards program is not subject to regulatory oversight in the Cayman Islands or any other jurisdiction, and it is not regulated by any governmental authority or regulatory body. Your participation is subject to the terms & conditions that you signed with Anchorage Digital Neo Ltd at onboarding.
Participation carries inherent risks, including but not limited to the risk of loss of funds, lack of recourse in case of disputes, and potential volatility of a stablecoin's value. You are responsible for understanding and complying with all applicable laws, regulations, and requirements in your jurisdiction, and you should conduct your own research and seek appropriate professional advice before enrolling.
# APT staking
Source: https://docs.anchorage.com/knowledge-base/platform/users/staking/apt
Stake Aptos (APT) to delegation pools and staking contracts, and manage staking rewards.
Aptos is a Layer 1 proof-of-stake blockchain developed by former Meta engineers who worked on the Diem project. The network stands out for its use of the Move programming language and a parallel execution engine, which allow it to process multiple transactions concurrently, aiming for high throughput and low latency.
Anchorage Digital offers support for Aptos including custody and staking:
* Custody your tokens (deposit and withdraw)
* Stake APT to any delegation pool validator and collect rewards
* Initialize and manage staking contracts with the validator provider of your choice
You can initiate every APT staking operation yourself, in the iOS app and in the web dashboard. Operations initiated in the web dashboard are endorsed in the iOS app — see [Staking overview](/knowledge-base/platform/users/staking/overview) for how policies and quorums apply.
Minimum iOS app version needed to perform APT staking operations: 2.96.0
Initializing a staking contract requires iOS 2.117.0 or later. On earlier versions the form is disabled with a prompt to update.
## Staking approaches
An Aptos validator needs 1M APT of active stake to participate in consensus and earn rewards. There are two ways to get there, and they differ in who funds the pool and how commission is set.
Stake alongside other delegators in a validator's shared pool, from an 11 APT minimum. The validator sets the commission.
Fund a validator's pool on your own, from a 1M APT minimum, and negotiate the commission directly with your provider.
Delegation pools are shared, so rewards start flowing once the pool as a whole crosses the 1M APT threshold, and the validator takes its commission from every delegator's rewards. A staking contract is yours alone: you front the stake, no one else can delegate into it, and the commission you agree with your provider is enforced on-chain.
Every validator is also capped at 50M APT of stake, whichever approach you use. Amounts offered in each form are net of the network fee and your operational reserve, so the maximum you see is what's actually stakeable.
## Starting a position
Tap the vault, select the wallet, then choose the action for your model. Fill in the fields below, add a comment (optional), then review and approve. Once the operation's quorum policy is met, the operation will be signed and broadcast on-chain.
### Stake with Delegation Pool
* **Delegation pool address** — the address of the validator's pool you're delegating to
* **Amount** — at least 11 APT per call
### Initialize Staking Contract
A staking contract separates three roles, each identified by its own Aptos address. You're the **owner**, funding the contract from your Anchorage Digital wallet, and you name an **operator** to run the validator node and a **voter** to cast governance votes for the stake. Your validator provider gives you the operator address and the commission you've agreed on.
* **Operator address** — the account that runs the validator node and receives the commission
* **Operator commission** — the share of rewards paid to the operator, from 0 to 100 percent
* **Voter address** — the account authorized to vote on governance proposals for this stake
* **Amount** — at least 1M APT, up to 50M APT or your available balance, whichever is lower
If you already hold a position with that pool or operator, use **Add Stake** on the position instead — a staking contract can only be initialized once per operator.
## Managing a position
The same three actions cover both models. Go to the wallet screen, tap **View details**, select the position, then choose an action. Each one is a separate operation subject to your quorum policy.
* **Add Stake** — enter an amount, capped by your available balance and the validator's remaining headroom under the 50M APT cap
* **Unlock Stake** — enter an amount, which defaults to your full active stake and can't exceed it
* **Withdraw Stake** — delegation pools take an amount, which defaults to everything past the cooldown
**Add Stake** and **Unlock Stake** also show the position's pool or operator address, filled in and not editable. **Withdraw Stake** has no address field, and on a staking contract it has no fields at all — withdrawing from a staking contract always releases every token past the cooldown at once, so there's nothing to enter.
Whichever action you take, if the validator isn't in the active consensus set you'll see a warning after you submit. Stake held outside the consensus set doesn't earn rewards until that validator joins.
## Unlock timing
Unbonding periods on Aptos are tied to a fixed 14-day validator unlock cycle, for both delegation pools and staking contracts. When you unlock, your funds are released at the end of that cycle. Depending on when you submit, you might wait as little as a few hours, or as long as the full 14 days, before you can withdraw the balance.
To find out how much time remains on a given validator's unlock cycle, search the validator's page on the Aptos block explorer. Here is an [example](https://explorer.aptoslabs.com/validator/0x2ded75e99c6efbe143a9648a3e88ebf9d0cf249b2af44d510bdd0287e8adcc79?network=mainnet) for the Anchorage Digital validator.
## When to contact us
You no longer need to contact us to stake, add, unlock, or withdraw APT — all of it is self-service. Reach out to your Anchorage Digital point of contact for changes to an existing staking contract's details, specifically its operator address, voter address, or commission rate.
# AVAX staking
Source: https://docs.anchorage.com/knowledge-base/platform/users/staking/avax
Stake Avalanche (AVAX) on P-Chain.
Avalanche is a high-performance, layer-one blockchain designed for superior speed, sub-second transaction finality, and high-throughput dApp development. Avalanche uses a multi-chain architecture with specialized chains (X, C, and P-chains) to enhance scalability and interoperability while remaining fully compatible with Ethereum's smart contracts.
## Overview
### Specialized chains
* **P-Chain (Platform Chain)** — the layer responsible for staking. Anchorage labels the P-Chain native asset `AVAX_PCHAIN`.
* **C-Chain (Contract Chain)** — an EVM-compatible smart contract layer used for deploying decentralized applications (dApps) and executing standard DeFi transactions. Anchorage labels the C-Chain native asset `AVAX`.
### Supported features
| Feature | Details |
| ------------------- | -------------------------------------------------- |
| **C-Chain custody** | Deposit and withdrawals |
| **P-Chain custody** | Deposits only |
| **C-Chain staking** | Not applicable to C-Chain |
| **P-Chain staking** | Staking AVAX\_PCHAIN from Anchorage Digital |
| **Liquid staking** | AVAX staking via the BENQI liquid staking protocol |
| **Bridging** | Bridging both ways between C-Chain and P-Chain |
No support for transfers for AVAX\_PCHAIN. Once you deposit or bridge AVAX to a P-Chain address, you can only bridge back to C-Chain to access funds. If you need to split AVAX across different P-Chain addresses, you will need to bridge separately to the different addresses from C-Chain or directly transfer P-Chain AVAX to those addresses.
No unstaking AVAX. The AVAX validator you stake to has staked for a specific time period. If you stake to a validator, your assets will be staked to that validator for the duration of the staking period. No unstaking is possible on the Avalanche network. Plan accordingly when choosing the validator you will stake to, depending on when the validator's staking period ends.
**Operate your own validator.** Anchorage Digital also supports operating your own AVAX validator. To enable this feature, contact your Relationship Manager. For the full process, see [Stake your own validator](#stake-your-own-validator).
Bridging is a two-part process. When you bridge AVAX between C- and P-Chain, the bridging requires two separate operations that need to be initiated. For example, you first need to export from C-Chain (Part 1) and then go to your P-Chain wallet and initiate the import operation (Part 2) to complete bridging.
## General steps to stake AVAX
1. Deposit AVAX to your Anchorage wallet.
2. Bridge AVAX to your Anchorage P-Chain wallet.
3. Stake AVAX\_PCHAIN to any validator on the Avalanche network (you will stake for the duration of the validator's staking period).
4. At the end of the staking period, your staked principal AVAX plus your staking rewards will return to the P-Chain wallet you staked from.
5. You can bridge back from P-Chain to C-Chain or re-stake.
## Bridge from C-Chain to P-Chain
Create a P-Chain wallet (`AVAX_PCHAIN`) that will receive your bridged assets.
Navigate to your C-Chain AVAX wallet.
Tap the **Stake** button, then tap **Export to p-chain**. Enter the amount to bridge and select the P-Chain wallet that will be your Destination Address.
Initiate the operation and gather quorum approvals.
After the operation completes, navigate to the Destination Address P-Chain wallet. Tap **Import from c-chain**, then tap **Next**. The amount you exported is automatically populated. Add an optional comment, then tap **Review**. Review the operation and tap **Submit and approve**.
## Bridge from P-Chain to C-Chain
You need to deposit a tiny amount of AVAX into the destination C-Chain wallet in order to complete the bridging process.
Create a C-Chain wallet (`AVAX`) that will receive your bridged assets. Deposit a small amount of AVAX to the wallet.
Navigate to your P-Chain AVAX\_PCHAIN wallet.
Tap the **Stake** button, then tap **Export to c-chain**. Enter the amount to bridge and select the AVAX wallet that will be your Destination Address (you must select a C-Chain wallet with a tiny amount of AVAX to complete bridging).
Initiate the operation and gather quorum approvals.
After the operation completes, navigate to the Destination Address C-Chain wallet and tap the **Stake** button.
If the **Stake** button is greyed out, tap the **Hide card** link below it to see the additional options.
Tap **Import AVAX from p-chain**, then tap **Next** to complete the import. Review the amount to import (automatically populated for you), add an optional comment, then tap **Review**. Review the operation and tap **Submit and approve**.
## Stake AVAX\_PCHAIN
When you delegate to an existing validator, you choose a staking duration of at least 14 days and at most 365 days. Your chosen duration must end on or before that validator's own staking period ends.
Navigate to your AVAX\_PCHAIN wallet.
Tap the **Stake** button, then tap **Stake** in the drop-down.
Enter the validator address that you wish to stake to. To delegate to an Anchorage Digital validator, use one of these NodeIDs:
* `NodeID-J6og828vTYU1Vpb5MET9MT7JS6iqMjRSC`
* `NodeID-CLquKzhJZaQ2B5XxpKnk3HjnRsp6GXQoG`
Your staked amount will be locked to this validator for the duration of the validator's staking period. Choose a validator that matches your need for staking and liquidity.
Enter the amount you wish to stake.
Minimum stake amount is 25 AVAX + 0.05 AVAX for fees.
Tap **Preview operation**, then tap **Confirm and submit for approval**.
Have your team members quorum approve the operation.
## Stake your own validator
Anchorage Digital also supports operating your own validator on the Avalanche network. To enable this feature, contact your Relationship Manager.
Before you begin, gather your validator's **NodeID**, **BLS public key**, and **BLS signature** (proof of possession). You also need a minimum of 2,000 AVAX\_PCHAIN in your P-Chain wallet.
Navigate to your AVAX\_PCHAIN wallet.
Tap the **Actions** button, then select **Create Validator**.
Complete the fields:
* **Node ID** — your validator's NodeID.
* **Public Key** — your BLS public key.
* **Signature** — your BLS signature (proof of possession).
* **Staking Rewards Commission** — the commission you charge delegators, pre-filled at 5% and adjustable.
* **Amount** — the amount to stake, or tap **Set max**. The minimum is 2,000 AVAX plus 0.05 AVAX for fees.
* **Duration** — the number of days the validator will be active, from a minimum of 14 days to a maximum of 365 days.
* **Staking Reward Address** — the wallet where your validator rewards are deposited.
* **Delegation Reward Address** — the wallet where commission from your delegators is deposited.
Tap **Preview operation**, review the details, then tap **Confirm and submit for approval**.
Have your team members quorum approve the operation.
Your validator stake is locked for the full duration you set and can't be unstaked early.
## Unstake AVAX\_PCHAIN
No unstaking operations exist on the Avalanche network. When you stake, you must stake for the duration of the period that validator is staking. Review the list of active Avalanche validators to find one that meets your staking duration needs.
## AVAX\_PCHAIN staking rewards
Rewards are distributed at the end of the staking period. They do not auto-compound during the lockup; you must restake them after they unlock to compound your returns. Staking rewards will be recognized at the end of the staking duration period with a specific operation.
# BTC staking with Babylon
Source: https://docs.anchorage.com/knowledge-base/platform/users/staking/babylon-btc
Stake Bitcoin using the Babylon Genesis protocol.
Babylon Genesis is a Bitcoin (BTC) staking protocol that lets holders earn rewards by helping secure other proof-of-stake (PoS) networks. Anchorage Digital is a day-one integrator of Babylon Genesis, enabling institutions to stake BTC and collect rewards directly through the Anchorage platform.
Anchorage Digital supports the following for BTC staking with Babylon Genesis:
* Stake BTC to any Finality Provider
* Collect BABY rewards on the Babylon Genesis chain
Minimum iOS app version required to perform BTC staking operations: **2.87.0**
You'll need a Taproot wallet on Bitcoin to stake BTC, and a BABY wallet on Babylon Genesis to collect rewards. You can create both wallets directly from the Anchorage Digital platform.
The timelock for BTC staked with Babylon Genesis is approximately 15 months; however, you may unstake your BTC at any time with a 7-day unbonding period.
## Getting started: Create a Taproot wallet
BTC staking with Babylon Genesis must be performed from Taproot wallets on the Bitcoin network.
Navigate to the desired vault and tap **Deposit**.
Select the asset option **Bitcoin**.
Select the **Create new wallet** icon and choose the address type **Taproot**.
Taproot wallet addresses will display with the Taproot badge and begin with the characters `bc1p...`.
Once you have funded your Taproot wallet with BTC, you will also need to create and fund a BABY wallet on the Babylon Genesis chain.
Creating new BTC staking positions with Babylon Genesis triggers two on-chain transactions — one on Bitcoin and one on Babylon Genesis. In order for the operation to be successful, each wallet must have funds available to pay their respective transaction fee.
## How to stake
Staking BTC can be initiated both in the iOS app and on the web dashboard.
Navigate to the desired vault, select the Taproot wallet, then tap **Stake with Babylon**.
Accept the Babylon Bitcoin Staking Terms.
Input the Finality Provider public key to which you would like to stake.
The public key for Anchorage Digital's finality provider is `c405fd997340c532a3b788b3186e779ed7cf9b5f2d6b8c8ad2351d82cfd0fb87`.
Enter the amount of BTC you would like to stake.
Designate which BABY wallet you would like to receive rewards.
In order for a wallet to be eligible as the reward recipient, it must be funded with a balance to cover gas fees.
Once a BABY wallet is linked for receiving rewards from BTC staking through a particular Finality Provider, it cannot be used to receive rewards through a different Finality Provider.
**Example:** If you have staked from Taproot Wallet 1 to Finality Provider 1 with the reward recipient set to BABY Wallet 1, then going forward BABY Wallet 1 will not be a valid option for staking BTC through any Finality Provider other than Finality Provider 1. If you decide to stake BTC again through Finality Provider 1, you may set the reward recipient to BABY Wallet 1 again, or to any other BABY wallet that has not yet been used for receiving rewards through another Finality Provider.
Select the **Preview operation** button to review and initiate the BTC staking operation. Endorse the staking operation via the iOS app.
New BTC staking positions take approximately 5 hours (30 Bitcoin blocks) to activate and begin accruing rewards. Following this time delay, a separate operation will automatically be triggered to register the BTC delegation on the Babylon Genesis chain.
The default timelock duration for BTC staking is about 15 months (64,000 Bitcoin blocks). You can view the remaining timelock duration for any staking position from the Staking Positions screen.
## How to unstake
You can unstake your position at any time before the timelock expires. Unstaking can be performed in two ways:
Wait for the \~15-month timelock to expire, then simply collect your inactive BTC stake back to your Available balance.
Request to early unbond your BTC stake position at any time before the default timelock duration expires. The Babylon Genesis protocol applies a 7-day unbonding period (1,008 Bitcoin blocks) for this path.
### Early unbonding path
#### Step 1: Early unstake
Go to the wallet screen and tap **View positions**.
Select the staking position you want to unstake, then select **Unstake** from within the three-dots button.
Proceed to review the operation and endorse in the iOS app.
Once the Early Unstake operation has completed, the BTC will display with the **Unstaking in progress** balance state.
#### Step 2: Collect
After the 7-day unbonding period has elapsed, the BTC will move into the **Inactive stake** balance state and be ready to Collect.
Return to the wallet screen and tap **View positions**.
On the corresponding staking position, select **Collect** from within the three-dots button.
Proceed to review the operation and endorse in the iOS app.
Each BTC stake position is distinct and can only be unstaked in its entirety — no partial unstaking of individual staking positions.
Unstaking BTC does not automatically claim accrued rewards. Rewards earned from BTC staking must be claimed from the corresponding BABY wallet on the Babylon Genesis chain.
## Claim rewards
Rewards from BTC staking with Babylon Genesis accrue on the Babylon Genesis chain, and can be claimed by the BABY wallet that was designated when the BTC staking position was originally created.
Navigate to the BABY wallet screen and tap **View details** or **Claim rewards**.
From the "BTC staking rewards" section, select the **Claim rewards** option from within the three-dots button.
Proceed to review the operation and endorse in the iOS app.
A single BABY wallet can be earning rewards from both BTC staking and BABY staking at the same time. Rewards from each source must be claimed separately.
There is no option to auto-claim BABY rewards earned from BTC staking. The auto-claim and stake feature is available for BABY rewards earned from BABY staking.
# BNB staking
Source: https://docs.anchorage.com/knowledge-base/platform/users/staking/bnb
Stake BNB and manage staking positions.
BNB Smart Chain is an EVM-compatible layer-1 blockchain secured by proof-of-stake consensus. Holders of BNB, the network's native token, can earn rewards by staking and participating in network security.
Anchorage Digital offers support for BNB including custody and staking:
* Custody your BNB (deposit and withdraw)
* Stake BNB to one or more supported validators and earn rewards
* Move stake between supported validators (redelegate) without waiting out the unbonding period
## Understanding your BNB balances
BNB staking is auto-compounding — rewards are added directly to your staked position rather than accruing as a separate rewards balance. The different balances you might see in your wallet include:
| Balance type | Description |
| :------------ | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Available** | Your spendable BNB balance — what you can freely transfer or stake. |
| **Staked** | BNB that's actively delegated to a validator. Because rewards auto-compound, this balance increases over time as rewards are distributed — there's no separate rewards balance to collect. |
| **Unstaking** | BNB you've requested to unstake. Funds remain here during the network's 7-day waiting period and can't be transferred or re-staked. |
| **Claimable** | BNB whose waiting period has ended and is ready to be claimed. Claiming is a separate, manual step that returns the funds to your available balance. |
You can have multiple unstaking requests in progress at the same time.
## How to stake
Tap the vault, select the wallet, then tap **Stake**.
Pick a validator from the dropdown, then tap **Next**.
Enter the amount you want to stake, then tap **Next**. The minimum staking amount is 1 BNB.
View the amount of tokens to be staked. Tap **Review** after adding a comment (optional) to review and approve the operation. Once the operation's quorum policy is met, the operation will be signed and broadcast on-chain.
## BNB rewards
When you stake your BNB, the protocol automatically re-stakes your rewards. Rewards are distributed once daily at approximately 00:00 UTC and will be added to your staking balance.
## How to unstake
Unstaking requires you to initiate two operations: 1) unstake and 2) claim.
### Step 1: Unstake
Go to the wallet screen and tap **View details**.
Select the staking position from which you'd like to unstake. Tap the **\[ ··· ]** button in the staking position card, then tap **Unstake**.
Enter the amount you want to unstake from this staking position.
View the amount of tokens to be unstaked. Tap **Review** after adding a comment (optional) to review and approve the operation. Once the operation's quorum policy is met, the operation will be signed and broadcast on-chain.
You'll need to wait until the network's 7-day unbonding period ends before your BNB is available to claim back to your wallet.
### Step 2: Claim
Go to the wallet screen and tap **View details**.
Select the staking position from which you'd like to claim. Tap the **\[ ··· ]** button in the staking position card, then tap **Claim**.
Enter the amount you want to claim from this staking position and tap **Next**. Tap **Review** after adding a comment (optional) to review and approve the operation. Once the operation's quorum policy is met, the operation will be signed and broadcast on-chain.
## Moving stake (redelegating)
You can move some or all of your stake from one validator to another without going through the 7-day unbonding period. To redelegate, open the staking position, tap **Redelegate**, and select the new validator. Note:
* You can only move stake to validators on Anchorage Digital's supported list.
* The network charges a small fee of 0.002% when moving stake, so the receiving validator will receive slightly less than the amount moved.
## Why staked and unstaked amounts may vary slightly
The amount of BNB you enter when unstaking or redelegating may differ slightly from the amount you actually receive or move. This is expected behavior inherent to how BNB staking works on-chain — it is not an error.
### Why this happens
BNB staking contracts don't track balances in BNB directly. Instead, each validator issues **shares**, and your position is held as a fixed number of shares whose BNB value fluctuates. When you enter a BNB amount, it's converted to a share count, and that share count is fixed for the operation. Between the moment you initiate the operation and the moment it's approved and broadcast, the share-to-BNB conversion rate can change — for example, when daily rewards are distributed at approximately 00:00 UTC, or when any participant on the network delegates, undelegates, or redelegates with the validator. As a result, the fixed share count may correspond to slightly more or less BNB than the figure originally entered.
### What to expect
* **Prompt approvals minimize variance.** If an operation is initiated, approved, and broadcast quickly, any difference is typically limited to rounding in the smallest decimal places (as small as 0.000000000000000001 BNB).
* **Delays can increase variance.** If network events occur between initiation and broadcast — such as the daily rewards distribution — the difference may be more noticeable. Absent a slashing event on the validator, you shouldn't receive meaningfully less than the amount you requested.
* **Operation history reflects the amount at initiation.** The amount shown on an operation record captures the value when the operation was created and may not exactly match the amount that settled on-chain. Your balances always reflect what's actually recorded on-chain, so you may occasionally see small balance adjustments on wallets with active staking positions.
These small variances are a property of the underlying protocol, not of the Anchorage Digital platform. All on-chain movements are captured in your reporting through the web dashboard and API.
# CELO staking
Source: https://docs.anchorage.com/knowledge-base/platform/users/staking/celo
Stake, unstake, and manage CELO rewards.
Celo is a public, open-source, proof-of-stake blockchain designed to facilitate a global payment infrastructure for mobile users. CELO is the utility and governance token for Celo.
Anchorage Digital offers support for Celo (CELO), including custody and delegation:
* Custody your CELO (deposit/withdraw)
* Delegate and undelegate CELO to any validator
* Collect and delegate your rewards
## Key features
"Voting" is the term used on Celo to represent the act of staking CELO.
Clients stake CELO by first locking the amount of CELO they wish to stake on the Anchorage Digital app. CELO must be locked before staking to prevent it from being transferred. Locked CELO can be used to participate in governance proposals, even if it is used in staking.
**Important notes:**
* It takes three days to unlock tokens.
* There is a waiting period of one to two days before clients can accumulate rewards from staking.
* Collected rewards are automatically added to the voting (staking) pool, so rewards will automatically re-delegate over time.
## Preparing your account for staking
1. Locate the CELO group vault and select **Start voting**.
2. Review and accept the disclosures to proceed.
3. Select **Contact Anchorage Digital to get started** to activate your account for voting.
1. After account activation, tap **Continue** to lock CELO assets for voting.
2. Enter the amount of CELO to stake and select **Lock for Voting** to proceed.
3. Tap **Submit & lock** to confirm.
Biometric approval is not required to lock CELO.
## How to stake CELO
After activating your account and locking your CELO assets, you can stake CELO directly on the Anchorage Digital iOS app:
Find the CELO vault and select **Vote**.
Tap **Vote for validator group**.
Enter the validator group's address and the amount of CELO to stake.
Review and confirm the operation.
Quorum approval is required when staking CELO.
## How to unstake CELO
Locate the CELO vault and tap **Vote**.
Tap on the validator to unstake CELO.
Select **Withdraw votes**.
Enter the amount of CELO you wish to unstake.
Select **Review and submit** to confirm.
Clients successfully unstake CELO once their quorum approves the operation.
## How to increase or decrease staked CELO
Clients may adjust the amount of staked CELO at any time in order to increase or decrease their "voting power":
Locate the validator used to stake CELO assets and tap **Adjust**.
Tap **Lock CELO** to increase your voting power or tap **Unlock CELO** to decrease your voting power.
Enter the amount you would like to lock or unlock.
Review and confirm the operation.
Biometric approval is not required for this operation.
## How to participate in on-chain governance
Clients may also vote on governance proposals:
Locate the **Governance** tab and tap on a governance proposal.
Submit a vote by choosing an option and tap **Vote**.
Clients successfully participate once their quorum approves the operation.
# COSMOS ecosystem staking
Source: https://docs.anchorage.com/knowledge-base/platform/users/staking/cosmos
Stake ATOM and other Cosmos ecosystem assets.
Anchorage Digital offers custody and staking for the following Cosmos ecosystem assets:
A layer-1 smart contract platform built on the Cosmos SDK that uses proof-of-stake consensus. BLD allows holders to vote on proposed network changes and collect rewards for helping secure the network.
A layer-1 blockchain and cross-chain communication platform enabling Web3 interoperability. AXL allows holders to collect rewards for helping secure the network.
Babylon Genesis is a Layer 1 blockchain and the first Bitcoin Secured Network (BSN), enabling Bitcoin staking and enhancing the security of decentralized applications by leveraging Bitcoin's security without bridges, wrapping, or smart contracts.
The Cosmos Hub serves as the economic center of the Cosmos ecosystem and provides interchain services to connected blockchains. ATOM allows holders to collect rewards for helping secure the network.
An open decentralized finance platform. DYDX allows token holders to engage in on-chain staking and voting regarding protocol and related proposals.
A layer-1 blockchain connected to the Cosmos ecosystem and interoperable with Ethereum. EVMOS allows holders to collect rewards for helping secure the network.
A layer-1, PoS blockchain built using the Cosmos SDK. OSMO allows holders to vote on proposed network changes and collect rewards for helping secure the network.
A public, open-source PoS blockchain for financial services offering ledger, exchange, and disintermediated lending. HASH is the utility and governance token for Provenance Blockchain.
An open-source, layer-1 blockchain offering cross-chain identity and digital asset management. RMO allows token holders to collect rewards for helping secure the network.
## Key features
For each supported blockchain, Anchorage Digital offers:
* Custody your tokens (deposit and withdraw)
* Stake and unstake to any validator
* Claim rewards
Tendermint protocols refer to this function as delegation. For purposes of this guide, this functionality is referred to as staking.
Screenshots below are shown for AXL as an example. The screens follow the same pattern for other assets in this guide, though the validator address format and available options vary by network.
## How to stake
Tap the vault, select the wallet, then tap **Stake** to review and accept the disclosures.
If applicable, select **Start auto-claim & stake rewards** to automatically claim and stake your rewards.
Enter the validator address and amount.
After adding a comment (optional), review and approve the operation details.
Once the operation's quorum policy is met, the operation will be signed and broadcast on-chain.
## How to increase the staked amount
To increase your staked amount or to stake to a different validator:
Navigate to the wallet screen.
Tap **View details** and then **Stake**.
Enter the validator address and amount.
After adding a comment (optional), review and approve the operation details. Once the operation's quorum policy is met, the operation will be signed and broadcast on-chain.
## How to auto-claim and stake rewards
To enable auto-claiming and staking of rewards, navigate to the wallet screen and toggle the feature on. The toggle is off by default, so rewards accrue unclaimed until you enable it or claim manually. Once enabled, rewards will be automatically claimed and staked every day. Gas fees will be deducted from the accrued rewards, as set by the network conditions. If rewards are insufficient to cover gas fees, the operation will fail.
Auto-claim and stake is not available for DYDX\_CHAIN.
Navigate to the wallet screen and toggle **Auto-claim and stake rewards** on or off as applicable.
## How to claim rewards
Navigate to the wallet screen and tap **View details**.
Select the validator from which you want to claim your rewards and tap **Claim rewards**.
After adding a comment (optional), review and approve the operation details. Once the operation's quorum policy is met, the operation will be signed and broadcast on-chain.
## How to unstake
Go to the wallet screen and tap **View details**.
Select the validator that holds the tokens you want to unstake, then tap **Unstake**.
Enter the amount to unstake, then tap **Next**.
After adding a comment (optional), review and approve the operation details. Once the operation's quorum policy is met, the operation will be signed and broadcast on-chain.
# EigenLayer restaking
Source: https://docs.anchorage.com/knowledge-base/platform/users/staking/eigenlayer
Restake ETH and EIGEN tokens with EigenLayer using Anchorage Digital.
EigenLayer is a protocol built on Ethereum that introduces restaking, a new primitive in cryptoeconomic security. This primitive enables the reuse of ETH on the consensus layer.
Users that stake ETH natively or with a liquid staking token (LST) can opt-in to EigenLayer smart contracts to restake their ETH or LST and extend cryptoeconomic security to additional applications on the network to earn additional rewards.
## EIGEN restaking with EigenLayer
In addition to EIGEN, Anchorage Digital supports restaking for a selection of other liquid staking tokens (LSTs) with EigenLayer.
### Add EigenLayer to your account's connected apps allowlist
In order for your Anchorage Digital wallet to be allowed to interact with the EigenLayer dApp, one of your account administrators must first add EigenLayer to your account's connected apps allowlist.
See [Adding apps to your approved list](/knowledge-base/platform/users/on-chain-interactions) to complete this step.
### Restake and delegate EIGEN
This process requires three on-chain transactions:
1. Approve EIGEN for use by the EigenLayer smart contracts
2. Deposit/Restake EIGEN to the EigenLayer smart contracts
3. Delegate your restaked balance to the operator of your choice
Each on-chain transaction will be initiated directly from the EigenLayer dApp.
Use WalletConnect to establish a connection between your desired Anchorage Digital wallet and the EigenLayer dApp webpage. Please reference Connect iOS app to external apps for instructions on using WalletConnect.
The first time a wallet establishes a connection with the EigenLayer dApp, you will be presented with the dApp's Terms of Service to sign. Upon pressing the **Sign** button, your Anchorage Digital wallet will automatically sign this off-chain transaction. There is no quorum approval needed to complete this step. Please allow a few minutes for your Anchorage Digital wallet to sign and return the signature response back to the dApp.
You may monitor the status of this operation in the Activity section of your Anchorage Digital iOS app. Once complete, the EigenLayer dApp interface will close the Terms of Service popup and allow you to proceed.
Continue by selecting EIGEN from the list of assets. Select the button labeled **Restake** to initiate the first operation.
Once initiated, an operation titled **Approve \[TOKEN]** will appear within the Anchorage Digital iOS app for review and quorum approval. Once the Approve transaction has been completed, you may proceed to restaking EIGEN.
From the EigenLayer interface, select the button labeled **Restake** (same as before) to initiate the operation.
Once initiated, an operation titled **EigenLayer Restake** will appear within the Anchorage Digital iOS app for review and quorum approval.
Once the Restake transaction has been completed, your EIGEN balance will display as **Restaked** within the Anchorage Digital iOS app. You may now proceed to delegating EIGEN.
From the EigenLayer interface, navigate to the Operator page and select any available operator to open their delegation page. Select the button labeled **Delegate** to initiate the operation.
Once initiated, an operation titled **EigenLayer Delegate** will appear within the Anchorage Digital iOS app for review and quorum approval.
Once the Delegate transaction has been completed, your EIGEN balance will display as **Restaked Delegated** within the Anchorage Digital iOS app. Your tokens are now eligible to earn rewards.
This EigenLayer delegation step is applied at the wallet-level. This means that any other tokens restaked to EigenLayer from this wallet will inherit this same delegation status, until you undelegate from the operator.
### Claim rewards
Rewards in EigenLayer come from actively validated services (AVSs), each of which control the distribution schedule, weight, and token type of their rewards. Once you have accrued rewards, visit the Dashboard screen of the EigenLayer interface and select the button labeled **Claim rewards**.
You will be presented with a selection menu of which reward tokens you would like to claim. You can either claim for all tokens, or select specific tokens to claim. Once you have made your selection, press the button labeled **Claim \[X] tokens**.
Anchorage Digital will only permit claiming of reward tokens that are actively supported for custody on the platform. This means that you may be delayed or prevented from claiming some rewards while restaking to EigenLayer from Anchorage Digital.
Once initiated, an operation titled **EigenLayer Claim Rewards** will appear within the Anchorage Digital iOS app for review and quorum approval.
### Unstake EIGEN
From the EigenLayer interface, select the button labeled **Unstake** to initiate the operation. You may unstake your full position or a partial amount.
EigenLayer contracts enforce a multi-day withdrawal delay for all unstaked tokens. Unstaking does not auto-claim any accrued rewards. It is recommended to first unstake, then claim rewards as some rewards may be distributed after unstaking.
Once initiated, an operation titled **EigenLayer Unstake** will appear within the Anchorage Digital iOS app for review and quorum approval.
Once the Unstake transaction has been completed, your EIGEN balance will display as **Unstaking** within the Anchorage Digital iOS app for several days.
Once the escrow period completes, your unstaked EIGEN balance will become withdrawable. From the EigenLayer interface, select the button labeled **Withdraw** to initiate the final step.
Once initiated, an operation titled **EigenLayer Withdraw** will appear within the Anchorage Digital iOS app for review and quorum approval.
Once the Withdraw transaction has been completed, your EIGEN will return to the **Available balance** state within the Anchorage Digital iOS app.
## ETH restaking with EigenLayer
To participate in native ETH restaking with EigenLayer, complete four on-chain transactions:
1. Create an EigenPod
2. Stake ETH for EigenLayer
3. Activate staked balance for restaking
4. Delegate to an operator
Aside from step 2 ("Stake ETH for EigenLayer"), which is performed from within the Anchorage Digital iOS app, all steps related to EigenLayer restaking are initiated directly from the EigenLayer dApp at [https://app.eigenlayer.xyz/](https://app.eigenlayer.xyz/)
### Prerequisites
In order for your Anchorage Digital wallet to be allowed to interact with the EigenLayer dApp, one of your account administrators must first add EigenLayer to your account's Connected Apps allowlist. See [Adding apps to your approved list](/knowledge-base/platform/users/on-chain-interactions) to complete this step.
### Native ETH restaking steps
Use WalletConnect to establish a connection between your desired Anchorage Digital wallet and the EigenLayer dApp webpage. Reference Connect iOS app to external apps for instructions on using WalletConnect.
The first time a wallet establishes a connection with the EigenLayer dApp, you will be presented with the dApp's Terms of Service to sign. Upon pressing the **Sign** button, your Anchorage Digital wallet will automatically sign this off-chain signature. There is no quorum approval needed. Please allow a few minutes for the signature to be returned to the dApp.
You may monitor the status of this operation in the Activity section of your Anchorage Digital iOS app. Once complete, the EigenLayer dApp interface will close the Terms of Service popup.
Continue by selecting **Natively Staked Ether** from the list of assets. Select the button labeled **Create EigenPod**.
Once initiated, an operation titled **Create EigenPod** will appear within the Anchorage Digital iOS app for review and quorum approval.
Once the transaction has been completed, you should see the EigenPod address display within the EigenLayer dApp.
Immediately following the completion of this operation, the Anchorage Digital iOS app will automatically initiate another operation to add this new EigenPod address as a "Trusted Smart Contract" for your wallet. This is an important security step that ensures your wallet is permitted to interact only with known valid smart contracts.
Review this operation to confirm the EigenPod address is correct. Once this **Add Trusted Smart Contract** operation is complete, you may proceed to the next step.
Within the Anchorage Digital iOS app, navigate to the same wallet that was used for creating the EigenPod in the previous step. Select the **Stake with EigenLayer** button.
Anchorage Digital will automatically detect that an EigenPod exists for this wallet, and will set the withdrawal address for this stake operation to be equal to the wallet's EigenPod address.
Double-check the EigenPod address shown in the iOS app matches the EigenPod address shown for the wallet on the EigenLayer dApp interface.
Tap **Continue** to review and endorse the operation.
Once the Stake ETH transaction has been completed, your staked ETH will move through the activation process. Once your validators are active and your staked ETH balance displays as **Staked** in the Anchorage Digital iOS app (several hours later), you can proceed to step 3.
Return to the EigenLayer dApp interface. You should see your staked ETH balance as **Awaiting Restake**. Select the **Restake** button.
Once initiated, an operation titled **EigenLayer Restake ETH** will appear within the Anchorage Digital iOS app for review and quorum approval.
If you decide to stake more ETH with EigenLayer through the same wallet, you will need to complete this Restake step again to activate the newly staked balance for restaking.
You may now proceed to step 4, "Delegate to an Operator."
From the EigenLayer dApp interface, navigate to the Operator page and select the operator to which you would like to delegate. Select the **Delegate** button.
Once initiated, an operation titled **EigenLayer Delegate** will appear within the Anchorage Digital iOS app for review and quorum approval.
Once the Delegate transaction has been completed, your ETH balance is now eligible to collect EigenLayer rewards.
This EigenLayer delegation step is applied at the wallet-level. This means that any other tokens restaked to EigenLayer from this wallet will inherit this same delegation status. A wallet can only be delegated to one operator at a time.
### Claim rewards
When participating in native ETH restaking with EigenLayer, a wallet will accrue two different types of rewards:
**AVS rewards**
AVS rewards in EigenLayer come from actively validated services (AVSs), each of which control the distribution schedule, weight, and token type of their rewards. Once you have accrued rewards, visit the Dashboard page of the EigenLayer interface and select the button labeled **Claim rewards**.
You will be presented with a selection menu of reward tokens that can be claimed. You can either claim all tokens, or select specific tokens to claim. Once you have made your selection, press the button labeled **Claim \[X] tokens**.
Anchorage Digital will only permit claiming of reward tokens that are actively supported for custody on the platform. This means that you may be delayed or prevented from claiming some rewards while restaking to EigenLayer from Anchorage Digital.
Once initiated, an operation titled **EigenLayer Claim Rewards** will appear within the Anchorage Digital iOS app for review and quorum approval.
**Consensus layer rewards**
Consensus layer rewards come from your native ETH validators. These are the same rewards you would collect from regular ETH staking, but now they accrue to your EigenPod. You have two options for handling these accrued rewards:
* **Restake rewards** — From the EigenLayer dApp interface, select **Restake** to begin a two-step process to convert your rewards into actively restaked shares. The operations are titled **EigenPod Start Checkpoint** and **EigenPod Complete Checkpoint**.
* **Unstake rewards** — From the EigenLayer dApp interface, select **Queue withdrawal** to begin a two-step process. The first operation will begin a 7-day unbonding period, and the second operation will complete the process by moving your unstaked ETH balance from EigenLayer into your Available balance.
### Unstake and withdraw native ETH
Fully unstaking your ETH from Ethereum validators and from the EigenLayer protocol is a three-step process.
The Ethereum and EigenLayer protocols enforce unbonding periods of several days between each of these three steps.
Within the Anchorage Digital iOS app, navigate to the wallet that is staking ETH with EigenLayer. Select the **Unstake** button.
Enter the number of validators you would like to unstake. Tap **Continue** to review and endorse the operation.
Once the Unstake transaction has been completed, your ETH will go through a 1–10 day unbonding period before moving to your EigenPod.
Return to the EigenLayer dApp interface. From the Restake page, find the Withdrawals section to view your ETH balance that is "Available to Queue."
Select the button labeled **Queue Withdrawal** and input the amount you wish to queue for withdrawal.
Once initiated, an operation titled **EigenLayer Unstake** will appear within the Anchorage Digital iOS app for review and quorum approval.
Once the Unstake transaction has been completed, your ETH balance will display as **Unstaking** within the Anchorage Digital iOS app for the duration of the escrow period (\~7 days). Once the escrow period completes, your ETH balance will become withdrawable.
From the EigenLayer interface, select the button labeled **Withdraw** to initiate the final step.
Once initiated, an operation titled **EigenLayer Withdraw** will appear within the Anchorage Digital iOS app for review and quorum approval.
Once the Withdraw transaction has been completed, your ETH will return to the **Available balance** state within the Anchorage Digital iOS app.
# ETH staking
Source: https://docs.anchorage.com/knowledge-base/platform/users/staking/eth
Stake Ethereum (ETH) and manage validators.
Ethereum is a layer-1 blockchain designed to enable decentralized applications on its network. The network is secured using a proof-of-stake consensus mechanism, and its native token, ETH, allows token holders to collect rewards for helping secure the network by validating transactions.
Anchorage Digital offers custody and staking services for Ethereum:
* Custody your ETH (deposit and withdraw)
* Stake ETH to a dedicated validator and collect rewards
Staking operations can be initiated both in the iOS app and on the web dashboard.
## Pectra upgrade
In 2025, Ethereum introduced the Pectra upgrade, which made several changes to the protocol's staking system. Anchorage Digital supports the new post-Pectra standard for ETH staking.
Any ETH staked prior to support of the new post-Pectra standard will remain on 0x01 validators (pre-Pectra). Upon request, Anchorage Digital will consolidate your ETH staked to 0x01 validators (pre-Pectra) into 0x02 validators (post-Pectra). Consolidation is irreversible.
### Summary of changes
| Dimension | 0x01 validators (pre-Pectra) | 0x02 validators (post-Pectra) |
| ----------------------------------- | ----------------------------------------------------------------- | --------------------------------------------------- |
| **Rewards** | Do not compound. Swept to available custody balance periodically. | Auto-compounded to the validator's staking balance. |
| **Supported staking amounts** | Increments of 32 ETH only | Between 32–2,048 ETH per validator |
| **Partial withdrawals / unstaking** | | |
| **Validator top-ups / add stake** | | |
| **Consolidation target** | | |
| **Anchorage Digital API support** | | |
## 0x02 validator staking (post-Pectra)
This staking path is available to Ethereum wallets with no ETH staking activity prior to April 2026.
### Fund a new validator
Navigate to the wallet from which you would like to stake. Select the **Stake** button to review and accept the staking terms and disclosures.
Enter the amount you would like to stake, between 32 ETH and 2,048 ETH.
Review the operation details, add a comment (optional), then submit the operation. Once the operation's quorum policy is met, the staking operation will be signed and broadcast on-chain.
The length of the activation queue is determined by network activity. A newly funded validator may take a few days or several weeks to become active and begin accruing rewards.
### Add or remove stake from an active validator
Navigate to the wallet with an active staking position. Select the **Actions** drop-down, then choose **Staking details** to view your position. Each staking position is identified by its validator public key.
Select **Add stake** or **Unstake** within the desired staking position card to initiate the corresponding action.
Review the operation details, add a comment (optional), then submit the operation. Once the operation's quorum policy is met, the staking operation will be signed and broadcast on-chain.
Unstaking a validator's total balance exits the validator from the active set. It will no longer be available for staking actions.
### Unstake a validator's total position
Navigate to your ETH wallet's staking details screen.
Select **Unstake**, then select **Set max** for the amount.
Review the operation details, add a comment (optional), then submit the operation. Once the operation's quorum policy is met, the unstaking operation will be signed and broadcast on-chain.
The length of the unstaking queue is determined by network activity. Partial and full unstakes may take a few days or several weeks to return funds to your available balance.
## 0x01 validator staking (pre-Pectra)
This staking path is only available to Ethereum wallets with ETH staking activity prior to April 2026. New staking positions and stake increases are not supported for 0x01 validators.
### How to stake
Tap the vault that holds the assets. Tap **ETH** to select the wallet you'd like to stake from.
Tap **Stake**, then tap **Continue** to review and accept the Ethereum staking disclosures. Enter the number of validators you would like to fund and tap **Continue** to review the operation and submit biometric approval.
Navigate to the vault and open the **ETH** wallet you want to stake from. In the wallet, find the **Staking** section and click **Stake**. Enter the number of validators you would like to fund, then review and confirm the operation details and submit. Go to the iOS app and endorse the staking operation.
### Ethereum staking rewards
Staking rewards are automatically deposited into your Anchorage Digital wallet (the wallet from which you staked). For any validator that has a balance greater than 32 ETH, the amount over 32 will be routinely withdrawn to your available balance. This sweep of any validator balance over 32 ETH will occur automatically approximately every ten days.
### How to unstake
Full staking withdrawals are initiated via the iOS app or the web dashboard and involve unstaking the full amount of 32 ETH that was initially staked to a validator.
Unstaking is subject to an unbonding period determined by network conditions.
**iOS:**
From the vault page, tap **ETH** and select the wallet with your staked ETH, then tap **Unstake**. Enter the number of validators you would like to unstake and tap **Continue** to review the operation and submit biometric approval.
**Web dashboard:**
Navigate to the vault on the web dashboard, select the wallet with your staked ETH, hover over the address field, and click **Unstake**. Enter the number of validators you would like to unstake and proceed to preview the operation. Review the operation details and click to submit biometric approval in the mobile app.
## Frequently asked questions
No action is needed as rewards are routinely deposited to your available balance.
A full staking withdrawal occurs in two parts:
1. **Exit the active validator set** — Once a request to "exit" has been made, the validator is added to the exit queue. If there are no other validators in the exit queue, this part will take approximately 35 minutes. If there are other validators in the exit queue, this part can take several days or weeks.
2. **Withdraw balance back to the execution layer** — Once exited, a validator must wait a minimum of 27 hours to be considered "withdrawable." At this point, the exited and withdrawable ETH will be picked up in the next recurring withdrawal sweep which has a \~ten day cycle.
For further questions related to ETH staking, please contact your client experience manager.
# FLOW staking
Source: https://docs.anchorage.com/knowledge-base/platform/users/staking/flow
Stake FLOW tokens and manage delegations.
Flow is a fast, decentralized, and developer-friendly blockchain, designed as the foundation for a new generation of games and apps. Flow apps keep users in control of their own data, create new kinds of digital assets tradable on open markets, and build open economies owned by the users that help make them valuable.
The Flow token (FLOW) is the native currency for the Flow network. Token holders collect rewards by staking their FLOW and working to secure the network.
## Definitions
* **Unlocked Flow tokens** — FLOW that is available for immediate withdrawal and deposits. Flow rewards are a type of unlocked Flow token.
* **Locked Flow tokens** — Unvested FLOW tokens that vest over time.
## Key features
Anchorage Digital offers support for Flow custody and staking. Clients may:
* Create deposit addresses and withdraw unlocked FLOW
* Custody locked FLOW that is subject to a vesting schedule
* Delegate FLOW to Anchorage Digital or third-party validators
* Re-delegate FLOW rewards automatically
* Collect Flow rewards and unlocked Flow when FLOW starts to vest
* Operate their own Flow validator and stake from Anchorage Digital custody
* Lease tokens from Dapper Labs and operate a validator using Anchorage Digital
## Moving Flow tokens to Anchorage Digital
### If you hold unlocked Flow tokens
Contact your Anchorage Digital client experience manager and specify the Anchorage Digital vault that you want to hold FLOW tokens.
Anchorage Digital will enable Flow for deposits and withdrawals for your organization.
You can create a Flow deposit address from your Anchorage Digital vault.
### If you hold locked Flow tokens in self-custody, another custody provider, or Dapper Labs
Contact your Anchorage Digital client experience manager and specify the Anchorage Digital vault that you want to hold FLOW tokens.
If applicable, Anchorage Digital will share your new Flow address with your custody provider and confirm with them that you wish to custody with Anchorage Digital.
Unstake your FLOW tokens with your custody provider or from self-custody, if applicable. After you unstake, wait one to two weeks for the unbonding period. Please complete your unstake transaction right before the epoch ends on Tuesdays 8am PST to minimize your waiting time.
If applicable, you will co-authorize a transaction with Dapper Labs to unlock your FLOW, transfer FLOW back to Dapper Labs, and Dapper Labs will redeliver your locked FLOW to your Anchorage Digital vault.
Your new vesting contract is now in safe Anchorage Digital custody and your balance will be updated within 48 hours.
## Participating in Flow staking
Anchorage Digital supports staking on the Flow blockchain. You will be able to participate by delegating your Flow assets to a validator and collect rewards for keeping the network secure.
From the Anchorage Digital app, you can delegate and undelegate your Flow tokens to either the Anchorage Digital validator or a third-party validator. If you have locked Flow, you will be able to delegate your locked Flow and collect rewards.
For further questions related to Flow (FLOW), please contact your client experience manager.
# FOGO staking
Source: https://docs.anchorage.com/knowledge-base/platform/users/staking/fogo
Stake Fogo (FOGO) to a validator and manage stake accounts.
Fogo is a high-performance, fully SVM-compatible layer-1 blockchain that runs the same native programs as Solana (System, Vote, Stake), secured by proof-of-stake consensus. Holders of FOGO, Fogo's native token, can earn rewards by staking and participating in network security.
## Understanding your FOGO balances
Due to Fogo network requirements, Anchorage will hold a small amount of FOGO in your account. The different balances you might see in your wallet include:
| Balance type | Description |
| ----------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Available** | Your spendable FOGO balance, which you can freely transfer or stake. |
| **Staked** | FOGO that is actively delegated to a validator. |
| **Staking Reserve** | A small buffer of FOGO set aside to cover the transaction fees associated with managing your stake accounts. It ensures you always have enough FOGO to perform staking operations, such as unstake and collect, on existing staked positions. |
| **Rent Reserve - Wallet** | A small amount of FOGO locked to keep your wallet account alive on-chain. |
| **Rent Reserve - Stake Account(s)** | FOGO locked aside to keep your stake account(s) alive. Fogo requires every on-chain account to maintain a minimum balance to stay "rent-exempt." |
None of these reserves are fees, and all remain part of your account.
## How to stake
Tap the vault, select the **FOGO** wallet, then tap **Stake**.
Enter the validator's **vote account address**, then tap **Next**. Fogo does not show a validator drop-down, so enter the vote account directly. The address must be a valid, currently-existing FOGO vote account, or the operation is rejected before signing. Use the reference list below to choose a validator.
Enter the amount you wish to stake, then tap **Next**. The minimum stake amount is 100.01 FOGO.
Optionally add a comment, then read the **Fogo (FOGO) Staking Terms** disclosure. Scroll to the bottom and tap **Accept**, then tap **Review** to approve. Once the operation's quorum policy is met, the operation is signed and broadcast on-chain.
After staking, your stake begins a warmup of \~1 epoch before it becomes active. During warmup the position shows `Staking in progress`; once active it shows `Staked`. View it under **Total staked → Staking positions** (tap **View details**).
### Fogo validators reference list
You can stake to any valid, currently-existing FOGO vote account. Before submitting, Anchorage checks the address against the live network validator set and rejects anything that isn't a real vote account. The list below is **not** an Anchorage-approved set. It's a point-in-time snapshot of the validators currently on Fogo mainnet, to help you choose.
Snapshot as of May 27, 2026. Fogo mainnet currently runs a curated set of validators (Zone 1 / APAC), all charging 10% commission. The active set can change, so verify current validators before staking. You delegate to the vote account address.
| # | Validator | Vote account address | Approx. stake | Commission | Site |
| - | -------------------------- | ---------------------------------------------- | ------------- | ---------- | ----------------- |
| 1 | Asymmetric Research | `DvcNfyebCWAmZLBVziziKotGcAAaPcRSV11ofZyrd83s` | \~129.6M | 10% | asymmetric.re |
| 2 | Hikari | `H1KAR1BGuhaR5mRE8mHmdYPdiZgFwK2cax2FoYYvBwNK` | \~128.6M | 10% | hikaritrade.xyz |
| 3 | Fogees Hub | `Fogeep8H4S7uLn2uQxJAsjWKRK2ZF4gEoh1Qs3PPvWy` | \~122.0M | 10% | fogees.link |
| 4 | xLabs | `xLUSQcsEw5SdcqTvcPzp5vKA73hgpxgZdjiZYivthnx` | \~119.8M | 10% | xlabs.xyz |
| 5 | Kairos Research × Firstset | `HdRqqKbcgYtoBSZSCBLbKH67862f77qwHGersbqTWp21` | \~118.1M | 10% | x.com/Kairos\_Res |
| 6 | (no registered name) | `DPebxDKSC678HxLZJ1V7PgjfsfGfAnmEDTerXwBggbpv` | \~129.3M | 10% | N/A |
| 7 | (no registered name) | `FLVAzAUpGEtmndEsSqmAoYUEmUE5tENiwpWTRgJX6BUS` | \~121.6M | 10% | N/A |
## Fogo rewards
When you stake your FOGO, the protocol automatically re-stakes your rewards. Rewards are calculated at each epoch boundary and added directly to your active stake (auto-compounded). There is no claim transaction and no separate "available to claim" balance.
A Fogo epoch is much shorter than Solana's: Fogo runs \~40ms blocks, so epochs are on the order of hours and rewards post several times a day.
Fogo uses a multi-local ("zone") consensus system where one zone of validators is active per epoch. If your validator's zone is inactive for an epoch, that stake earns no rewards for that epoch.
## How to unstake
Unstaking requires you to initiate two operations: 1) unstake and 2) collect.
Unstaking a position splits its stake account, so both the amount you unstake and the amount left staked must each stay at or above the network minimum (about 100 FOGO). If a position holds less than roughly twice the minimum, you'll be asked to unstake the full position rather than a partial amount.
### Step 1: Unstake
Go to the wallet screen and tap **View details**.
Select the staking position from which you would like to unstake. Tap the **\[ ··· ]** button on the staking position card, then tap **Unstake**.
Enter the amount you wish to unstake from this staking position, then tap **Next**.
Tap **Review** after adding a comment (optional) to review and approve the operation. Once the operation's quorum policy is met, the operation is signed and broadcast on-chain.
You will need to wait until the current Fogo epoch ends before your FOGO is available to collect. During this time the position shows `Unstaking in progress` (Balances view: `Staked (Deactivating)`), then `Inactive stake` once complete.
### Step 2: Collect
Go to the wallet screen and tap **View details**.
Select the staking position from which you would like to collect. Tap the **\[ ··· ]** button on the staking position card, then tap **Collect**.
Enter the amount you wish to collect and tap **Next**. Tap **Review** after adding a comment (optional) to review and approve the operation. Once the operation's quorum policy is met, the operation is signed and broadcast on-chain. The FOGO returns to your wallet as `Available`.
## Position statuses
| Stage | Balances view | Staking view |
| ------------------------------- | ----------------------- | ----------------------- |
| After staking, during warmup | `Staking in Progress` | `Staking in progress` |
| Warmup complete (earning) | `Staked` | `Staked` |
| After unstake, during unbonding | `Staked (Deactivating)` | `Unstaking in progress` |
| Unbonding complete | `Inactive Stake` | `Inactive stake` |
| After collect | `Available` | n/a |
## Notes
* **Do I need to claim rewards?** No. Rewards auto-compound into your active stake every epoch. There's no claim button and no separate claimable balance.
* **Can I partially unstake?** Yes, within limits. Unstaking a position splits its stake account, and both the amount you unstake and the amount left staked must each stay at or above the network minimum (about 100 FOGO). In practice, a position must hold at least roughly twice the minimum to be partially unstaked; a smaller position must be unstaked in full.
* **Can I add to an existing stake?** No. Each stake creates a separate position, even to the same validator, and a stake account's delegation can't be topped up. To increase your staked amount, create a new stake; the positions are managed separately.
* **Is liquid staking (LSTs) supported?** No. FOGO is native staking only.
# HYPE staking
Source: https://docs.anchorage.com/knowledge-base/platform/users/staking/hype
Stake HYPE on HyperCore and manage HyperEVM/HyperCore wallets.
Hyperliquid is a decentralized exchange (DEX) specializing in high-speed perpetual futures trading, built on its own Layer 1 blockchain. Anchorage Digital supports staking on Hyperliquid, the process of delegating your native HYPE tokens to a validator to help secure the network and earn rewards.
## Key features
* Deposit your HYPE to either a HyperEVM or HyperCore wallet
* Bridge your HYPE back and forth between HyperEVM and HyperCore
* Move your HYPE back and forth between your HyperCore spot and stake accounts
* Stake and unstake your HYPE to any HYPE validator including the Anchorage validator
## Important considerations
**Operations & fees:** Operations can take up to 10 minutes to confirm on HyperCore. This limitation is due to the Hyperliquid public API.
**Bridging:** Before you bridge, you must have corresponding HYPE\_HYPEREVM and HYPE\_HYPERCORE wallets. For example, if you have 10 HYPE on a HYPE\_HYPEREVM wallet that you want to bridge, you first need to make sure you have a HYPE\_HYPERCORE wallet with the exact same address as the HyperEVM wallet.
Bridging from HyperEVM to HyperCore incurs transaction fees in HYPE tokens on HyperEVM. Bridging from HyperCore back to HyperEVM does not incur fees.
**Staking:** You can only stake to one validator per wallet. If you need to stake to multiple validators, please separate your HYPE tokens across wallets such that you stake to one validator per wallet.
**Rewards:** Anchorage Digital doesn't set or publish a fixed yield or APR for staking HYPE. Staking rewards automatically compound to the validator you are staking to. You do not need to claim rewards or re-stake them. All staking rewards are inflationary and come from the Hyperliquid protocol and the validator you choose, so they vary accordingly. Hyperliquid does not have MEV rewards.
**HyperCore Transfers:** Anchorage has limited support for transfers between HyperCore accounts. You can only transfer from one Anchorage HyperCore address to another if the destination address already holds a small amount of HYPE. If the destination address has a zero balance, the transfer will fail.
If you need to transfer HYPE between two internal HyperCore addresses, use one of the following methods:
* Bridge the assets back to HyperEVM, transfer them to the destination HyperEVM wallet, and then bridge them back to HyperCore.
* Deposit a small amount of HYPE + 1 USDC into the destination HyperCore address from an external wallet first. Anchorage does not support activating these new HyperCore wallets.
## How to deposit HYPE
### HyperEVM
If your HYPE is in HyperEVM, create a deposit address for the `HYPE_HYPEREVM` asset name.
Anchorage automatically creates the corresponding HyperCore address after you create a HyperEVM address.
As with all asset deposits, you will need to complete deposit attribution before you can interact with HyperEVM.
### HyperCore
If your HYPE is in HyperCore, create a deposit address for the `HYPE_HYPERCORE` asset name.
When you create a HyperCore wallet address, the first time you send HYPE to this newly created wallet, you will need to send 1 USDC to activate the HyperCore wallet. This is a one-time activation that must be completed by the sending wallet. Anchorage does not support sending this 1 USDC to HyperCore wallets at this time.
As with all asset deposits, you will need to complete deposit attribution before you can interact with HyperCore.
### Wallet addresses for privacy
HyperEVM and HyperCore wallets share addresses with other EVM blockchains at Anchorage. If you have created other EVM addresses for other networks and want a fresh new address for your HYPE deposits, you will need to create HyperEVM and HyperCore wallets that exceed the number of EVM wallet addresses you currently have.
**Example:** You have 25 EVM addresses already created for Arbitrum in your Anchorage vault. You want a fresh new HyperCore and HyperEVM wallet address for your HYPE tokens. You will need to create 26 new HyperCore and HyperEVM wallets in Anchorage. The first 25 wallets will share the same address as the Arbitrum wallets. The 26th HyperEVM and HyperCore wallet will be a fresh new address.
## How to bridge HYPE
### HyperEVM to HyperCore
Deposit attribution is required when bridging assets between HyperEVM and HyperCore. If you bridge from HyperEVM to HyperCore, your HYPE\_HYPERCORE tokens will be held in deposit attribution for you to attribute where the funds came from. After you complete deposit attribution, you will be able to initiate bridging.
Navigate to your HyperEVM wallet.
Click on the **Bridge to HyperCore** button.
To bridge on iOS, you will need to tap on **Hide card** before you will be able to view the **Bridge to HyperCore** button.
Enter the amount to bridge.
Click on the checkbox to acknowledge Terms.
Click on **Accept and preview operation**. Quorum approve the operation from the iOS app.
### HyperCore to HyperEVM
Navigate to your HyperCore wallet.
Click on the **Stake** button and then **Bridge**.
Enter the amount to bridge.
Click on the checkbox to acknowledge Terms.
Click on **Accept and preview operation**. Quorum approve the operation from the iOS app.
## How to move HYPE from spot to stake accounts
### HyperCore Spot to HyperCore Stake Account
Navigate to your HyperCore wallet.
Click on **Stake** and then **Move to stake balance**.
Enter the amount to move.
Click on the checkbox to acknowledge Terms.
Click on **Accept and preview operation**. Quorum approve the operation from the iOS app.
## How to stake and unstake HYPE
### Stake HYPE
You can only stake to one validator per wallet. If you need to stake to multiple validators, please separate your HYPE tokens across wallets such that you stake to one validator per wallet.
After you stake HYPE, the Hyperliquid protocol enforces a 24-hour waiting period before you can unstake. You cannot immediately unstake HYPE.
You must initiate and have your team quorum approve the staking operation within 48 hours due to limitations from the Hyperliquid protocol. If you quorum approve after 48 hours, the operation will fail on-chain and you will need to re-initiate the staking request.
Navigate to your HyperCore wallet.
Click on **Stake** and then **Stake more**.
Enter a valid validator address.
Anchorage operates an institution-grade Hyperliquid validator. The validator address is `0x420a4ed7b6bb361da586868adec2f2bb9ab75e66`.
Enter the amount to stake.
Click on the checkbox to acknowledge Terms.
Click on **Accept and preview operation**. Quorum approve the operation from the iOS app.
### Unstake HYPE
Unstaking is instant. The Hyperliquid protocol enforces a 7-day unbonding period when you move HYPE from your Stake to Spot accounts.
Navigate to your HyperCore wallet.
Click on **Stake** and then **View details**.
Click on the **Unstake** button, then click **Yes, proceed**.
Enter the amount to unstake.
Click on **Preview operation**. Quorum approve the operation from the iOS app.
## How to move unstaked HYPE from stake to spot account
### HyperCore Stake to HyperCore Spot Account
Moving HYPE from Stake to Spot account undergoes a 7-day unbonding period before your HYPE assets are available to bridge.
Navigate to your HyperCore wallet.
Click on **Stake** and then **Move to available balance**.
Enter the amount to move.
Click on the checkbox to acknowledge Terms.
Click on **Accept and preview operation**. Quorum approve the operation from the iOS app.
# HyperCore account linking
Source: https://docs.anchorage.com/knowledge-base/platform/users/staking/hypercore-linking
Link a staking account to a trading account on HyperCore to apply fee discounts.
You can link a staking account to a trading account on HyperCore. When linked, the staked HYPE held in your Anchorage Digital Bank staking account counts toward the fee discounts earned by an external trading account.
## Link your accounts
The external trading account must initiate the link request first. You can then finalize the link from your staking account.
Connect the external trading account to the HyperLiquid dApp and select **Link Staking**.
Go to the HyperCore wallet in your Anchorage Digital Bank vault.
Select **Actions**, then **Link Account**.
Enter the trading account address you want to link.
Review and approve the operation. Once the operation meets your quorum policy, it's signed and broadcast on-chain.
# MEZO staking
Source: https://docs.anchorage.com/knowledge-base/platform/users/staking/mezo
Lock BTC in the Mezo network.
Mezo is an EVM-compatible protocol that allows users to engage in a variety of DeFi activities using BTC, such as staking, borrowing, and lending, without needing to sell BTC. Mezo empowers BTC holders to put their assets to work and generate returns while maintaining their exposure.
## Overview
### What is MEZO?
Mezo enables BTC holders to bridge BTC to the Mezo network, lock assets to earn rewards, and participate in governance by pairing veBTC and veMEZO NFTs.
### How to receive your MEZO\_MEZO token distribution
Create a `MEZO_MEZO` wallet in your Anchorage organization and vault, then reach out to your Client Experience or Relationship Manager to set up distributions via Atlas.
### MEZO support on Anchorage Digital vs. Porto
* You can lock/stake BTC and MEZO on both Anchorage Digital and Porto.
* You can provide liquidity to pools on Mezo from Porto only. By providing liquidity and staking your LP position, you can earn more rewards from Porto.
### What happens with MEZO staking?
**BTC:**
* Users can bridge BTC to Mezo to receive BTC\_MEZO.
* Users can use their bridged BTC\_MEZO to stake and receive a veBTC NFT that represents your locked BTC.
* Users can pair your veBTC and veMEZO to boost rewards and vote on staking gauges.
**MEZO:**
* Users can use MEZO to stake and receive a veMEZO NFT that represents your locked MEZO.
* Withdraw your MEZO from veMEZO after the staking duration period completes.
* You must have a small amount of BTC\_MEZO in your wallet in order to lock MEZO.
## Important considerations
Use `anchorage.mezo.org` to access the Mezo dapp for Anchorage. `mezo.org` is the dapp found on the Mezo website but is not updated to work with Anchorage.
Locking your BTC\_MEZO for any duration locks your funds for the entire duration. Mezo does not allow unlocking before the lock period ends.
The minimum amount of BTC to bridge from the Bitcoin to Mezo network is 0.01 BTC.
Anchorage does NOT support MUSD borrowing on Anchorage Digital — you can use these features on Porto.
Transfers of your veBTC or veMEZO NFT must be initiated from the Anchorage iOS app (not the Anchorage client dashboard).
## Step 1: Connect Mezo to your Anchorage account
Log in to your Anchorage Digital account.
Create a `MEZO_MEZO` wallet under the vault you wish to use. We will call this wallet "Mezo Wallet #1."
Go to **Web3 > Add an App**. Select **Mezo** from the app dropdown. Choose the vaults with MEZO to connect. Add Mezo to the allowlist.
Go to `anchorage.mezo.org` and tap **Sign-in**. Click **Continue with Porto**, then click **WalletConnect**.
Go to your Anchorage iOS app and tap on the QR code button in the top right portion of the screen. Scan the QR code on the `anchorage.mezo.org` website.
Select "Mezo Wallet #1" as the wallet to connect to the Mezo dapp.
Accept the Terms of Service on the Mezo dapp. Create a username or skip to the Mezo dapp homepage.
## Bridging BTC
### Bridge BTC from the Bitcoin network to the Mezo network
Follow the steps to connect Mezo to your Anchorage account.
From the Mezo dapp homepage, click on **Deposit**.
Enter the amount of BTC you wish to bridge to Mezo.
Copy the BTC address and send your BTC to the Mezo address. After you send the BTC to the Mezo address, Mezo will send BTC\_MEZO to your Mezo address.
### Bridge BTC back from the Mezo network to the Bitcoin network
Follow the steps to connect Mezo to your Anchorage account.
From the Mezo dapp homepage, click on **Withdraw**. Enter the amount of BTC you want to bridge from Mezo back to the Bitcoin network.
Enter the BTC address that you wish to send the bridged BTC to. Click **Continue**.
Click on **Approve BTC for withdraw**. From the Anchorage iOS wallet, quorum approve the operation. Mezo will send the BTC back to your specified BTC address.
## Staking or locking BTC
### Locking BTC\_MEZO to receive rewards
Follow the steps to connect Mezo to your Anchorage account.
After you bridge BTC from the Bitcoin network to the Mezo network, you will see your BTC on Mezo from the Mezo dapp. From the Mezo dapp homepage, click on **Lock**.
Enter the amount of BTC\_MEZO you wish to lock. Enter the staking duration: 6, 13, 20, or 27 days.
Locking your BTC\_MEZO for any duration locks your funds for the entire duration. Mezo does not allow unlocking before the lock period ends.
Click the **Lock** button, then click **Approve**. Go to your Anchorage iOS app to quorum approve the operation. After you quorum approve, you may have to refresh the Mezo dapp to proceed to the next step.
Go back to the Mezo dapp and click the **Lock** button again. Go to your Anchorage iOS app to quorum approve the operation. After you quorum approve, the Mezo dapp will display your locked BTC as a veBTC NFT.
### Withdraw BTC\_MEZO from veBTC
Follow the steps to connect Mezo to your Anchorage account.
After you lock your BTC\_MEZO, you will see your veBTC on Mezo from the Mezo dapp. Click on **Withdraw All**, then click **Claim**, then click **Withdraw**.
Go to your Anchorage iOS app to quorum approve the operation. Have your team members quorum approve the operation from the Anchorage iOS app. Anchorage will risk review the operation. The withdraw will complete.
### Claim BTC\_MEZO from veBTC
Follow the steps to connect Mezo to your Anchorage account.
After you lock your BTC\_MEZO, you will see your veBTC on Mezo from the Mezo dapp. Click on **Claim**, then click the **Claim** button in the modal. The claim will complete.
## Staking or locking MEZO
### Locking MEZO\_MEZO
You must hold MEZO\_MEZO and BTC\_MEZO (for fees) in your wallet before you can lock.
Follow the steps to connect Mezo to your Anchorage account.
From the Mezo dapp homepage, click on **Lock**.
Enter the amount of MEZO\_MEZO you wish to lock and the staking duration.
Locking your MEZO\_MEZO for any duration locks your funds for the entire duration. Mezo does not allow unlocking before the lock period ends.
Click the **Lock** button, then click **Approve**. Go to your Anchorage iOS app to quorum approve the operation. After you quorum approve, you may have to refresh the Mezo dapp to proceed to the next step.
Go back to the Mezo dapp and click the **Lock** button again. Go to your Anchorage iOS app to quorum approve the operation. After you quorum approve, the Mezo dapp will display your locked MEZO as a veMEZO NFT.
### Withdraw MEZO\_MEZO from veMEZO
Follow the steps to connect Mezo to your Anchorage account.
After you lock your MEZO\_MEZO, you will see your veMEZO on Mezo from the Mezo dapp. Click on **Withdraw All**, then click **Claim**, then click **Withdraw**.
Go to your Anchorage iOS app to quorum approve the operation. Have your team members quorum approve the operation from the Anchorage iOS app. Anchorage will risk review the operation. The withdraw will complete.
## View your veBTC or veMEZO NFT
Go to your Anchorage vault where you hold the NFT.
Find the tabs for **Assets** and **NFT**, then click on **NFT**.
You will see your list of veBTC or veMEZO NFTs.
## Pair & boosting
### Pair your veBTC or veMEZO NFT
Go to the `anchorage.mezo.org` dapp. Click on the **Lock** tab on the sidebar.
Click on **Manage** next to the veMEZO you want to pair.
Tap on the **Pair & boost** button. Select the veBTC and veMEZO NFT you wish to pair. Click on the **Pair & boost** button.
Click on the **Create Gauge** button to start signing the transactions to pair.
Click the **Vote** button under Step 2: Vote on boost gauge. After your vote is confirmed, click on the **Apply boost** button in Step 3: Apply boost. You will see a confirmation screen showing your veBTC boosted from your veMEZO and your associated voting power.
## Voting
### Vote on staking gauges with your veBTC NFT
Click on the **Vote** tab on the sidebar after you pair and boost your veBTC.
Click on the **Manage** button next to your veBTC.
Allocate 100% of your voting power to the BTC/MUSD staking gauge.
This is the only staking gauge approved for Anchorage.
Click on **Submit vote** and sign the transaction from your Anchorage iOS app. View the "Vote completed" confirmation screen after your vote transaction completes.
# MON staking
Source: https://docs.anchorage.com/knowledge-base/platform/users/staking/mon
Stake MON tokens and manage delegations.
Monad is a high-performance, EVM-compatible Layer-1 blockchain delivering up to 10,000 transactions per second through novel architectural improvements. The network is secured using proof-of-stake consensus, and Monad's native token, MON, allows token holders to collect rewards for helping secure the network.
Anchorage Digital offers support for Monad including custody and staking:
* Custody your assets (deposit and withdraw)
* Stake MON\_MONAD to any validator and collect rewards
## How to stake
Tap the vault, select the wallet, then tap **Stake** to review and accept the disclosures.
Enter the validator ID and amount.
The validator ID is an integer value, not a wallet address (e.g., 24).
After adding a comment (optional), review and approve the operation details. Once the operation's quorum policy is met, the operation will be signed and broadcast on-chain.
## How to claim rewards
Go to the wallet screen and tap **View details**.
Select the position from which you want to claim your rewards and tap **Claim rewards**.
After adding a comment (optional), review and approve the operation details.
## How to unstake
Unstaking requires two operations: 1) unstake and 2) collect.
### Step 1: Unstake
Go to the wallet screen and tap **View details**.
Select the staking position from which you would like to unstake. Tap on the **\[ ··· ]** button in the staking position card, then tap **Unstake**.
Enter the amount to unstake. After adding a comment (optional), review and approve the operation details. Once the operation's quorum policy is met, the operation will be signed and broadcast on-chain.
You will need to wait until the next Monad epoch ends before your MON is available to collect back to your wallet. Epochs are about 5.5 hours long.
### Step 2: Collect
Go to the wallet screen and tap **View details**.
Select the staking position from which you would like to collect the Inactive Stake. Tap on the **\[ ··· ]** button in the staking position card, then tap **Collect**.
# Staking overview
Source: https://docs.anchorage.com/knowledge-base/platform/users/staking/overview
Earn staking rewards on supported assets.
## What is staking?
Many blockchains (called proof-of-stake networks) rely on participants locking up the network's own token to help validate transactions and keep the network secure. In return, the network pays rewards. Staking is the act of committing your assets to that process to earn those rewards.
For an institution, staking is a way to earn a return on assets you're already holding — comparable to yield on an idle balance — rather than letting them sit dormant. The trade-off is that staked assets are committed to the network and typically take time to unlock (an "unbonding" period that varies by asset).
With Anchorage Digital, you stake **without giving up custody**. Assets never leave your vault to a third-party staking provider; delegation, rewards, and unstaking all happen inside the platform under your existing policies and quorum approvals.
Anchorage Digital provides secure staking to our clients as part of our custody solution, supporting a wide range of proof-of-stake assets including Aptos, Celo, Ethereum, and others. Clients can stake assets directly through the Anchorage Digital platform or run their own validator.
Automatic re-delegation of staking rewards is available for select assets to keep them actively staked. Detailed reporting is accessible through the web dashboard or API for clients and fund administrators.
We regularly add support for new assets based on institutional demand.
## Policies and permissions
Staking-related operations fall under your organization's vault default policy or staking policy, if any. Administrators and members who have been added to the policy's quorum can initiate and approve staking operations on behalf of the organization.
## How to stake
You may initiate delegation in the iOS app and in the web dashboard. If initiated in the web dashboard, users are required to submit biometric approval in the iOS app.
Navigate to the vault and open the wallet holding the asset you want to stake. Staking is initiated from within the wallet — it's no longer a **Stake** action in the side navigation.
In the wallet, find the **Staking** section and click **Stake** to initiate a delegation.
Depending on the asset, enter the information requested for delegation.
Review and confirm the information, then submit. Go to the iOS app and endorse the staking operation.
## View staked balances
To view your staking balances and validators, open the wallet and go to the **Staking** section. You should be able to see the staked amounts, assets available to claim, and validator information.
## Changing validators
Redelegation—moving an existing delegation to a different validator without unstaking—isn't supported on all chains yet.
On chains where redelegation isn't supported, changing validators takes three steps: unstake the position, wait out the asset's unbonding period, then stake again to the new validator. Unbonding periods vary by asset—check the asset's staking page for details.
# SEI staking
Source: https://docs.anchorage.com/knowledge-base/platform/users/staking/sei
Stake Sei (SEI) to a validator, claim rewards, and unstake.
Sei is a high-performance layer-1 blockchain that uses Delegated Proof-of-Stake (DPoS) consensus and features full Ethereum Virtual Machine (EVM) compatibility. Holders of SEI, Sei's native token, can earn rewards by delegating their stake to a validator that helps secure the network.
The staking experience follows the same delegation model as other Tendermint assets: you delegate to a validator, rewards accrue separately and are claimed on demand, and unstaking begins a network unbonding period before your SEI returns to your available balance.
## Understanding your SEI balances
As your SEI moves through the staking lifecycle, it appears under different balance types in your wallet.
| Balance type | Description |
| ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Available** | Your spendable SEI balance, which you can freely transfer or stake. |
| **Staked** | SEI that is actively delegated to a validator and earning rewards. |
| **Available to claim** | Rewards that have accrued from your staked SEI and are ready to claim. These are not spendable and do not compound until you claim them. |
| **Unstaking** | SEI that you have unstaked and that is moving through the network's unbonding period. It is no longer earning rewards and cannot be transferred until unbonding completes. |
| **Staking Reserve** | A small amount of SEI (about 1 SEI) set aside to cover the transaction fees for managing your stake, such as unstaking and claiming. It remains part of your account. |
## How to stake
Tap the vault, select the **SEI** wallet, then tap **Stake**.
Enter the validator's **address**, then tap **Next**. The field defaults to the Anchorage Digital validator, and you can enter any valid Sei validator address (it starts with `seivaloper1`). The address is checked against the live network, and a validator that does not exist is rejected before signing.
Enter the amount you wish to stake, then tap **Next**. There is no minimum stake amount, but keep a small SEI balance available to cover transaction fees.
Optionally add a comment, then read the **Sei (SEI) Staking Terms** disclosure and tap **Accept**. Tap **Review** to approve. Once the operation's quorum policy is met, the operation is signed and broadcast on-chain.
After staking, your position briefly shows `Staking in progress` while the transaction confirms on-chain, then `Staked` once it is active and earning rewards. There is no waiting period for your stake to activate. View your positions under **View details** on the wallet screen.
## How to add to a stake or stake to another validator
Each wallet and validator pair is a separate staking position. Staking more to a validator you already use adds to that position, and staking to a new validator creates a new position.
Go to the wallet screen and tap **View details**, then tap **Stake**.
Enter the validator address and the amount you wish to stake, then tap **Next**.
Optionally add a comment, then tap **Review** to approve. Once the operation's quorum policy is met, the operation is signed and broadcast on-chain.
## SEI rewards
Your staked SEI earns rewards continuously as the network produces blocks. Rewards accrue separately for each validator you stake to and appear as an **Available to claim** balance.
Rewards do not auto-compound. To grow your position, claim your rewards and then stake them again. When you unstake a position, the network automatically claims that position's accrued rewards to your wallet as part of the unstake.
Rewards are tracked per validator, so the amount you can claim is shown for each of your staking positions. Claiming returns the full accrued amount for that position to your available balance.
## How to claim rewards
Go to the wallet screen and tap **View details**.
Select the staking position you want to claim from, then tap **Claim rewards**. Claiming returns the full accrued rewards for that position.
Optionally add a comment, then tap **Review** to approve. Claiming rewards requires initiator approval only, so no quorum or risk review is needed. The rewards return to your wallet as `Available`.
## How to redelegate
Redelegating moves staked SEI from one validator to another without unstaking first. Unlike unstaking, your SEI stays staked throughout, so it does not go through the unbonding period and continues earning rewards.
Go to the wallet screen and tap **View details**.
Select the staking position you want to move, then tap **Redelegate**.
Enter the address of the validator you want to move your stake to, then enter the amount you wish to redelegate and tap **Next**. As with staking, the destination validator address (it starts with `seivaloper1`) is checked against the live network before signing.
Optionally add a comment, then tap **Review** to approve. Once the operation's quorum policy is met, the operation is signed and broadcast on-chain.
While the change takes effect, the position shows `Restaking in progress`, then `Staked` under the new validator.
## How to unstake
Unstaking a SEI position takes a single operation. After you unstake, your SEI moves through the network's unbonding period and then returns to your available balance automatically. There is no separate collect step.
You can unstake a full or partial amount from a position. Any rewards that have accrued to the position are claimed automatically when you unstake.
Go to the wallet screen and tap **View details**.
Select the staking position you want to unstake from, then tap **Unstake**.
Enter the amount you wish to unstake, then tap **Next**.
Optionally add a comment, then tap **Review** to approve. Once the operation's quorum policy is met, the operation is signed and broadcast on-chain.
Your SEI begins a 21-day unbonding period, during which the position shows `Unstaking in progress`. Once unbonding completes, your SEI returns to your available balance automatically.
## Position statuses
| Stage | Status |
| ------------------------------------------------------ | ----------------------- |
| After staking, while the transaction confirms | `Staking in progress` |
| Delegation active and earning rewards | `Staked` |
| Rewards accrued and ready to claim | `Available to claim` |
| While a redelegation to another validator takes effect | `Restaking in progress` |
| After unstaking, during the 21-day unbonding period | `Unstaking in progress` |
## FAQ
* **Do I need to claim rewards?** Yes. SEI rewards do not auto-compound, so they stay in the **Available to claim** balance until you claim them or until you unstake the position, which claims them automatically.
* **Can I partially unstake?** Yes. You can unstake a full or partial amount from any staking position.
* **Can I add to an existing stake?** Yes. Staking more to a validator you already use adds to that position. Staking to a new validator creates a separate position.
* **Is there a minimum stake amount?** No. There is no protocol minimum, but keep a small SEI balance available to cover the transaction fees for staking, claiming, and unstaking.
* **Can I move stake between validators (redelegate)?** Yes. You can redelegate staked SEI from one validator to another without unstaking, so your SEI keeps earning rewards and does not go through the unbonding period. See [How to redelegate](#how-to-redelegate).
# SOL staking
Source: https://docs.anchorage.com/knowledge-base/platform/users/staking/sol
Stake Solana (SOL) and manage stake accounts.
Solana is a layer-1 blockchain designed to host decentralized applications, secured by proof-of-stake consensus. Holders of SOL, Solana's native token, can earn rewards by staking and participating in network security.
Anchorage Digital offers support for Solana including custody, staking, and liquid staking through JitoSOL:
* Custody your SOL (deposit and withdraw)
* Stake SOL to any validator and collect rewards
* Mint JitoSOL directly from the Anchorage Digital platform
## Understanding your SOL balances
Due to Solana network requirements, Anchorage will hold a small amount of SOL in your account. The different balances you might see in your wallet include:
| Balance type | Description |
| ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Available** | Your spendable SOL balance — what you can freely transfer or stake. |
| **Rent Reserve - Stake Account(s)** | SOL locked aside to keep your stake account(s) alive. Solana requires every on-chain account to maintain a minimum SOL balance to stay "rent-exempt." |
| **Rent Reserve - Wallet** | A small amount of SOL locked to keep your wallet account alive on-chain. |
| **Staked** | SOL that is actively delegated to a validator. |
| **Staking Reserve** | A small buffer of SOL set aside to cover the transaction fees associated with managing your stake accounts. It ensures you always have enough SOL to perform staking operations, such as unstake and collect, on existing staked positions. |
## How to stake
Tap the vault, select the wallet, then tap **Stake**.
Pick a validator from the drop-down or enter the validator's vote account address, then tap **Next**.
Enter the amount you wish to stake, then tap **Next**.
View the amount of tokens to be staked. Tap **Review** after adding a comment (optional) to review and approve the operation. Once the operation's quorum policy is met, the operation will be signed and broadcast on-chain.
## Solana rewards
Anchorage Digital doesn't set or publish a fixed yield or APR for staking SOL. Your rewards come from Solana's proof-of-stake protocol and the validator you choose, so they vary accordingly.
When you stake your SOL, the protocol automatically re-stakes your rewards. Rewards are distributed every epoch — approximately 1–2 day periods — and will be added to your staking balance.
If you stake to a validator running Jito, you will also receive a separate reward type called MEV rewards. These rewards are not automatically restaked on your behalf. Instead, these rewards are distributed to your SOL staking account in an inactive state and must be collected. See the unstaking steps below to collect inactive rewards.
## How to unstake
Unstaking requires you to initiate two operations: 1) unstake and 2) collect.
### Step 1: Unstake
Go to the wallet screen and tap **View details**.
Select the staking position from which you would like to unstake. Tap on the **\[ ··· ]** button in the staking position card, then tap **Unstake**.
Enter the amount you wish to unstake from this staking position.
View the amount of tokens to be unstaked. Tap **Review** after adding a comment (optional) to review and approve the operation. Once the operation's quorum policy is met, the operation will be signed and broadcast on-chain.
You will need to wait until the current Solana epoch ends before your SOL is available to collect back to your wallet. Epochs are typically 1–2 days.
### Step 2: Collect
Go to the wallet screen and tap **View details**.
Select the staking position from which you would like to collect the Inactive Stake. Tap on the **\[ ··· ]** button in the staking position card, then tap **Collect**.
Enter the amount you wish to collect from this staking position and tap **Next**. Tap **Review** after adding a comment (optional) to review and approve the operation. Once the operation's quorum policy is met, the operation will be signed and broadcast on-chain.
## JitoSOL mint and redeem
### Mint JitoSOL
To mint JitoSOL, follow the SOL staking flow and choose **JitoSOL (Liquid Staking)** from the available validator options.
### Redeem JitoSOL
To redeem JitoSOL for actively staked SOL, navigate to the wallet that holds `JITOSOL_SOLANA` and press **Redeem**.
Once the redemption operation is complete, the corresponding amount of actively staked SOL will appear in your wallet. You can then follow the SOL unstaking flow.
**Redeem one at a time.** You can only redeem JITOSOL\_SOLANA one operation at a time. Wait for your first redemption to complete before starting the second redemption.
**Redeeming over 40,000 JITOSOL\_SOLANA.** If you are redeeming more than 40,000 JITOSOL\_SOLANA, please split it into multiple transactions. To ensure success, keep each individual transaction at or below the 40,000 JITOSOL\_SOLANA limit.
This limitation is from the protocol and is necessary because very few Jito validators can process larger, single redemptions. Note that the 40,000 JITOSOL\_SOLANA limit is subject to change as the protocol evolves.
# STABLE staking
Source: https://docs.anchorage.com/knowledge-base/platform/users/staking/stable
Stablecoin staking rewards.
Stable is a high-performance, Layer 1 blockchain purpose-built for USDT settlement. The network uses USDT0 as the native gas token so that users transact entirely in a stable asset without managing volatile tokens.
The STABLE token is the governance and coordination token of the Stable network. It is not used for gas fees or everyday transactions — all gas fees on StableChain are paid in USDT0.
## Supported features
* **STABLE:** deposits, withdrawals
* **USDT0:** deposits, withdrawals
* **Staking:** stake STABLE tokens to validators on StableChain
* **Rewards:** claim rewards using your USDT0 wallet (no staking exists for USDT0)
Staking rewards are distributed as USDT0 — not STABLE.
## How to stake STABLE
Go to your STABLE wallet.
Tap **Actions → Stake** on web, or the **Stake** button on iOS.
Choose a validator.
Enter the stake amount.
Click **Next** on iOS or **Accept and preview operation** on web. Quorum approve the staking operation. After the staking operation completes, you will see your staking balance as "Staked" in your wallet.
## How to unstake STABLE
Go to your STABLE wallet.
Tap **Actions → Staking Details** on web, or the **View Details** button on iOS.
Tap the **Unstake** button on web, or the context button → **Unstake** button on iOS.
Enter the unstake amount.
Click **Next** on iOS or **Yes proceed** on web. Quorum approve the staking operation. After the unstaking operation completes, you will see your unstaked amount in your Available balance after the unbonding period.
## How to claim rewards
Staking rewards are distributed as USDT0. Navigate to the corresponding USDT0 wallet — if you stake from "Stable Wallet 1," your rewards will be ready to claim from the USDT0 wallet with the same wallet address.
Navigate to the corresponding USDT0 wallet.
Tap **Staking details** on web, or the **Claim rewards** button on iOS.
Tap the **Claim rewards** button on web, or the context button → **Claim rewards** button on iOS. This claims your full available rewards balance.
Click **Next** on iOS or **Yes proceed** on web. After the claim rewards operation completes, your rewards will be available in your USDT0 wallet.
# STRK staking
Source: https://docs.anchorage.com/knowledge-base/platform/users/staking/strk
Stake Starknet (STRK) tokens.
Starknet is a permissionless, decentralized Validity Rollup (also known as a ZK-Rollup) operating as a Layer 2 network on top of Ethereum. It uses STARK cryptographic proofs to achieve high throughput, low transaction fees, and verifiable computation while maintaining the security of the Ethereum mainnet.
Anchorage Digital offers support for Starknet including custody and staking:
* Custody your tokens (deposit and withdraw)
* Stake STRK\_STARKNET to any validator's delegation pool and earn rewards
* Stake supported BTC-wrapper tokens to any validator's delegation pool and earn rewards
Minimum iOS app version needed to perform staking operations: 2.99.0
## Bridge STRK from Ethereum to Starknet
STRK staking must be performed from the Starknet chain. If you have STRK on Ethereum that you would like to bridge to Starknet, please reach out to [accountexecutive@anchorage.com](mailto:accountexecutive@anchorage.com) and provide the following details:
* Source wallet (Ethereum address)
* Destination wallet (Starknet address)
* Amount of STRK tokens to bridge
## How to stake
Tap the vault, select the desired asset to stake, select the wallet, then tap **Stake** to review and accept the disclosures.
Enter the validator's pool contract address and amount.
Pool contract addresses are different for each token type.
Select which wallet from the vault to set as the reward recipient wallet. You may select the same wallet from which you are staking, or another wallet within the same vault.
Updating the reward recipient for a particular validator position will affect where all rewards go once claimed.
After adding a comment (optional), review and approve the operation details. Once the operation's quorum policy is met, the operation will be signed and broadcast on-chain.
## How to claim rewards
Go to the wallet screen and tap **View details**.
Select the position from which you want to claim your rewards and tap **Claim rewards**.
Rewards for BTC-wrapper staked tokens will accrue in the STRK\_STARKNET token.
After adding a comment (optional), review and approve the operation details. Once the operation's quorum policy is met, the operation will be signed and broadcast on-chain.
## How to unstake
Go to the wallet screen and tap **View details**. Select the validator from which you want to unstake and tap **Unstake**.
Enter the amount of tokens that you want to unstake and tap **Next**.
After adding a comment (optional), review and approve the operation details. Once the operation's quorum policy is met, the operation will be signed and broadcast on-chain.
# SUI staking
Source: https://docs.anchorage.com/knowledge-base/platform/users/staking/sui
Stake SUI tokens.
SUI is a layer-1 blockchain that is horizontally scalable to support the creation of rich and dynamic on-chain assets, while also offering instant settlement and high throughput. The network is secured using proof-of-stake consensus, and SUI's native token, SUI, allows token holders to collect rewards for helping secure the network.
Anchorage Digital offers support for SUI including custody and staking:
* Custody your tokens (deposit and withdraw)
* Stake SUI to any validator and collect rewards
## How to stake
Tap the vault, select the wallet, then tap **Stake** to review and accept the disclosures.
Enter the validator address and the amount you would like to stake.
Add a comment (optional), then tap **Review** to submit the operation. Once the operation's quorum policy is met, the staking operation will be signed and broadcast on-chain.
## How to unstake
Go to the wallet screen and tap **View details**. Select the validator from which you want to unstake, then tap **Unstake**.
Enter the amount of tokens that you want to unstake and tap **Review**.
Once the operation's quorum policy is met, the unstaking operation will be signed and broadcast on-chain.
# TRX staking
Source: https://docs.anchorage.com/knowledge-base/platform/users/staking/trx
Stake Tron (TRX) through freeze, vote, unstake, withdraw, and reward claim operations.
Tron is a high-throughput, layer-1 blockchain built for low-cost transactions and large-scale dApp and stablecoin activity. Tron uses a Delegated Proof-of-Stake (DPoS) model in which token holders stake TRX to obtain network resources and voting power, then vote for block producers (Super Representatives) to earn rewards.
## What Anchorage Digital supports
**Custody**
* TRX deposits and withdrawals
**Staking**
* Locking TRX for Tron Power (Freeze TRX)
* Voting your Tron Power to a Super Representative (Stake TRX)
* Claiming staking rewards
* Unstaking TRX (Unfreeze TRX)
* Moving unstaked TRX back to your wallet (Withdraw TRX)
TRX staking is a concierge service, not self-service. Operations are requested through your Relationship Manager and constructed manually by Anchorage Digital. Plan around operation lead time rather than expecting instant execution.
## Key considerations
* **14-day unbonding period.** When you unstake, your TRX enters a 14-day unfreeze waiting period on the Tron network before it can be withdrawn. Plan your liquidity around this window.
* **Rewards do not auto-compound.** Staking rewards accrue separately and must be claimed, then restaked, to compound. Anchorage Digital supports claiming at a default rate of once per month.
* **Resources are a side benefit.** Staking also grants Energy and Bandwidth used to pay for transactions on the Tron network.
## Balance types
As your TRX moves through the staking lifecycle, it appears under different balance types in your wallet.
| Balance type | Description |
| :----------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Inactive Stake – Frozen** | TRX frozen but not yet voted to a Super Representative. Tron Power has been granted but rewards are not accruing. This is the state after Freeze and before Stake. |
| **Staked** | TRX frozen and actively voted to a Super Representative. Fully earning rewards. Reflects a completed Freeze + Stake flow. |
| **Unstaking** | TRX unfrozen and in the Tron network's 14-day unbonding period. Votes are revoked; TRX is not earning rewards and cannot be withdrawn until the period completes. |
| **Unstaked – Available to withdraw** | TRX that has completed the 14-day unbonding period. A Withdraw operation is required to return it to your available wallet balance. |
| **Unclaimed rewards** | Voting rewards accrued from your Super Representative that have not yet been claimed. Not spendable and not auto-compounding. Claiming moves them to your available TRX balance. |
## Staking TRX
Staking requires two sequential operations: **Freeze TRX**, then **Stake TRX**.
### Freeze TRX
Request the freeze operation through your Relationship Manager or email [accountexecutive@anchorage.com](mailto:accountexecutive@anchorage.com).
Provide the amount of TRX to freeze, the wallet you will be staking from, and the Super Representative you will vote to.
Confirm the day and 24-hour time at which you would like to initiate and quorum approve the freeze operation.
On the agreed date, review the operation details provided by Anchorage Digital, then have your team quorum approve the operation. Anchorage Digital signs and broadcasts once quorum is met.
Your TRX is now frozen and you hold Tron Power, but rewards are not yet accruing — complete the Stake operation below.
### Stake TRX
Review the stake operation details constructed by Anchorage Digital, then have your team quorum approve the operation. Anchorage Digital signs and broadcasts once quorum is met.
Your TRX is now staked and actively earning rewards.
## Unstaking TRX
Unstaking requires two sequential operations: **Unstake TRX**, then **Withdraw TRX**, with a mandatory 14-day unbonding period between them.
### Unstake TRX
Request the unstake operation through your Relationship Manager or email [accountexecutive@anchorage.com](mailto:accountexecutive@anchorage.com).
Provide the amount of TRX to unstake and the wallet you will be unstaking from.
Confirm the day and 24-hour time at which you would like to initiate and quorum approve the unstake operation.
On the agreed date, review the operation details provided by Anchorage Digital, then have your team quorum approve the operation. Anchorage Digital signs and broadcasts once quorum is met.
Your TRX is now unstaking and begins the 14-day unbonding period. It cannot be withdrawn until the period fully elapses.
### Withdraw TRX
The withdraw operation can only be initiated after the 14-day unbonding period has fully elapsed.
After the 14-day period completes, confirm with your Relationship Manager the day and 24-hour time at which you would like to initiate and quorum approve the withdraw operation.
On the agreed date, review the operation details provided by Anchorage Digital, then have your team quorum approve the operation. Anchorage Digital signs and broadcasts once quorum is met.
Your TRX is now withdrawn and available in your wallet.
## Claim staking rewards
Claimed rewards are returned to your available TRX balance and do not auto-compound. To compound, restake the claimed TRX using the Freeze and Stake operations above.
Request the claim rewards operation through your Relationship Manager or email [accountexecutive@anchorage.com](mailto:accountexecutive@anchorage.com).
Provide the wallet you are claiming rewards for and confirm the day and 24-hour time at which you would like to initiate and quorum approve the claim operation.
On the agreed date, review the operation details provided by Anchorage Digital, then have your team quorum approve the operation. Anchorage Digital signs and broadcasts once quorum is met.
Your accrued rewards are now claimed and available as TRX in your wallet.
# Trading
Source: https://docs.anchorage.com/knowledge-base/platform/users/trading
Request quotes and execute trades via the RFQ system in the Anchorage Digital web dashboard.
The Anchorage Digital RFQ (Request for Quote) system is available 24/7/365 via the web dashboard and API. Quote requests are routed to top dealer desks to obtain the most favorable pricing. Quotes can be requested buy-side, sell-side, or two-way.
Trades settle on a net-settlement basis, typically end-of-day and no later than 24 hours post-trade. Confirmation statements are emailed immediately upon execution.
## Requesting trading access
If the **Trade** tab displays an access message, the user, organization, or both haven't been granted trading permissions. Contact Anchorage Digital to request access.
## Trading dashboard features
Once trading permissions are granted, you can:
Request quotes and execute buy, sell, or two-way trades with live 3-second quote windows.
Access all trade history and view settlement status for open positions.
View execution limits, outstanding amounts, and balances at the account level.
View pre-funded [USD](/knowledge-base/platform/users/usd-banking) or digital asset balances at the account level.
View wire instructions to transfer USD to Anchorage Digital for settlement.
View blockchain wallet addresses to transfer digital assets to Anchorage Digital.
## Requesting a quote and executing a trade
Select **Buy**, **Sell**, or **2 way**, then choose the exchange pair.
Enter the USD value or asset quantity (e.g., 10 BTC). For two-way quotes, both buy and sell prices are displayed simultaneously.
The quote is live for three seconds. Select **Execute buy** or **Execute sell** to execute. Select the refresh button above the execute button at any time to generate a new quote.
## Trade history and settlement status
View trade details and settlement status under the **Trades** tab.
| Status | Description |
| :------: | :------------------------------------------------------------------------------------------------------------ |
| Executed | The trade executed but neither party has sent the settlement amount due. |
| Settling | The client has sent their amount to Anchorage Digital, but the amount due to the client hasn't yet been sent. |
| Settled | Both sides have exchanged amounts due and the trade is fully settled. |
## Settlement timing
Settlement runs in a daily window with our liquidity providers, after which proceeds settle to your account. Plan around T+1: under the Hold agreement, trades settle no later than T+1, while legacy A1 agreements can allow longer. Settlement follows this cadence and can't be expedited.
## Cross-entity settlement
If one entity trades and a different entity funds the trade or receives the proceeds, an authorization or instruction letter is required before settlement. Prefunding thresholds are also set per agreement. Both are contract-driven — contact your account team to put them in place.
# Travel Rule
Source: https://docs.anchorage.com/knowledge-base/platform/users/travel-rule
Complete Travel Rule requirements for deposits and withdrawals between VASPs.
The Travel Rule requires originator and beneficiary information to accompany certain transfers between virtual asset service providers (VASPs). What you do depends on whether you're receiving or sending.
## Deposits
If the originating VASP isn't on the same Travel Rule network as Anchorage Digital, you complete a Travel Rule form for the deposit. The deposit proceeds in parallel while the information is collected, so funds aren't blocked waiting on the form.
## Withdrawals
If a withdrawal's Travel Rule transmission is rejected by the receiving VASP, the beneficiary VASP details are usually the cause. Confirm the beneficiary VASP is correct, and correct it if needed. The trusted destination may need to be re-created with the right details before you retry. See [Trusted destinations](/knowledge-base/platform/users/web-dashboard/trusted-destinations).
Travel Rule details differ for hosted and self-hosted destinations. A hosted destination is held at another VASP; a self-hosted destination is a wallet the recipient controls directly.
Separately from Travel Rule forms, our compliance team may ask you to confirm details about a specific transaction's originator or beneficiary. See [Responding to compliance RFIs](/knowledge-base/platform/users/compliance-rfi).
# Trusted destinations
Source: https://docs.anchorage.com/knowledge-base/platform/users/trusted-destinations
Add, manage, and remove pre-approved withdrawal addresses for crypto and USD.
A **trusted destination** is an external address or bank recipient your organization has added to its allowlist of approved recipients. Adding a trusted destination requires quorum approval up front, before any funds move to it. Once approved, you can withdraw to that destination without collecting a separate quorum approval for each transaction when using the API.
You can also configure a policy to only allow withdrawals to trusted destinations — turning the allowlist into a hard control rather than just a convenience. Add a conditional rule to the vault policy: set the condition to destination is any trusted address with a **Quorum** outcome, and set the base rule's outcome to **Block**. This rejects withdrawals to any address that isn't on your trusted destinations list. See [Rules](/knowledge-base/platform/users/rules) to add a conditional rule.
Adding a trusted destination follows your default administrator policy unless a custom trusted destination policy is configured — see [Administrator policy](/knowledge-base/platform/users/administrator-policy).
Adding a trusted destination requires biometric approval in the iOS app and quorum approval. Only administrators with trusted destination management permissions can add or remove trusted destinations.
## Crypto trusted destinations
Trusted destinations for crypto are **per-network**. The same address on Ethereum and on Base are two separate trusted destinations, so add one for each network you'll withdraw to. A withdrawal can fail if the address is allowlisted on a different network than the one you're sending on.
Smart-contract and program addresses can also be added as trusted destinations. Self-service whitelisting for program-derived (off-curve) addresses is coming soon — for now, contact your client experience team to add one on your behalf.
### Adding a single crypto trusted destination
In **Settings**, under **Trusted addresses**, select **Trusted destinations**, then select **Add**.
Select **Add single address**.
Select the asset, enter the address, provide a name and description, then select **Continue**.
Complete the address details form and select **Continue**. Optionally add a comment.
Review the operation details and select **Confirm and submit for approval**. Complete the endorsement process in the Anchorage Digital iOS app.
The AML field on a trusted destination isn't set during setup. It populates at withdrawal time from the latest prior transaction to that address and asset, so it can be empty on your first withdrawal and fills in automatically on subsequent ones.
### Adding multiple crypto trusted destinations
In **Settings**, under **Trusted addresses**, select **Trusted destinations**, then select **Add**.
Select **Upload multiple from file**.
Download the provided Excel spreadsheet template and fill it out in your preferred spreadsheet editor (Excel or Google Sheets). Save the completed file as a CSV.
Upload your completed CSV file to the web dashboard.
Review the list of trusted destinations, make any necessary adjustments, and select **Submit** for approval. Complete the endorsement process in the iOS app.
### Template fields
| Field | Description | Required when |
| :----------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------- |
| `destinationType` | The type of custodial provider: `Financial Institution` or `Self-Hosted Wallet`. | Always |
| `destinationDescription` | The name of the custodial provider (e.g., the name of a crypto exchange). | Always |
| `destinationCountry` | Two-letter country code for where the financial institution is incorporated. | `destinationType` is `Financial Institution` |
| `recipientType` | The ultimate beneficiary of the assets you're sending: `My Organization`, `Other Entity`, or `Other Person`. This is separate from `destinationOwner` below, which describes who owns the wallet address itself rather than who benefits from the assets. | Always |
| `recipientName` | Name of the beneficiary. | `recipientType` is `Other Entity` or `Other Person` |
| `recipientCountry` | Two-letter country code for where the beneficiary entity is incorporated or the beneficiary person resides. | `recipientType` is `Other Entity` or `Other Person` |
| `destinationOwner` | Owner of the self-hosted wallet address itself: `My organization` or `Other person or entity`. Separate from `recipientType` above. | `destinationType` is `Self-Hosted Wallet`, for ADS (Anchorage Digital Singapore) entities only |
The required fields above match the ones marked with a red asterisk in the downloadable template.
After uploading, Anchorage Digital parses the file and lets you review results and address any warnings or errors. If unresolvable errors are found, you'll need to correct and re-upload the file.
## USD trusted destinations
For USD withdrawals, you add the recipient's bank information as a trusted destination. See [USD withdrawals](/knowledge-base/platform/users/usd-withdrawals#adding-a-usd-trusted-destination) for the step-by-step process.
## Sending to your own org's addresses
You can add addresses that belong to your own organization as trusted destinations to tag and remember critical internal addresses. This is entirely optional — you don't need a trusted destination to send to your own vaults.
When withdrawing to an address your organization already controls, select the destination type that fits your workflow:
* **Another Vault** — sends to one of your own vaults directly. No trusted destination setup or per-request quorum approval is needed, making this the simplest path for routine internal movement.
* **Trusted Destination** — sends to a pre-approved, labeled address. Use this when you've added your own org's address as a trusted destination so your team can recognize it by name during future withdrawals.
If you're integrating via API and want to avoid per-transaction quorum for internal movements, use the [internal transfer API](/knowledge-base/platform/developers/move-money/transfer/crypto#internal-transfer) — it moves assets between your own wallets without allowlisting or quorum approval.
## After you submit
Adding or removing a trusted destination goes through two stages: your own quorum approves it, then Anchorage Digital reviews it. Our review usually finishes within 15 to 20 minutes of quorum being met, and often sooner.
Because the two stages run back to back, the wall-clock time from initiation to completion depends mostly on how quickly your approvers act. A request that looks slow has often been waiting on the last approver rather than on us — check the operation's status before escalating.
## Exporting trusted destinations
To get a full list of your organization's trusted sources and trusted destinations, ask your client experience team or email [accountexecutive@anchorage.com](mailto:accountexecutive@anchorage.com). A self-serve export isn't available today, so we produce the list for you.
## Editing trusted destinations
The address on a trusted destination can't be changed after submission — verify it carefully before you submit. To point at a different address, remove the existing trusted destination and add a new one. Both actions require quorum approval and Anchorage Digital review.
## Removing trusted destinations
In **Settings**, under **Trusted addresses**, select **Trusted destinations**.
Select the three-dot menu next to the trusted destination you want to remove.
Select **Remove**. Biometric approval in the iOS app is required. Once quorum is met, Anchorage Digital will review the operation.
# Trusted sources & deposit attribution
Source: https://docs.anchorage.com/knowledge-base/platform/users/trusted-sources-deposit-attribution
Manage trusted deposit sources and attribute pending crypto deposits.
When Anchorage Digital receives a crypto deposit that can't be automatically attributed to a known sender, one or more authorized users are notified by email to identify the sending party. Adding addresses to your trusted sources speeds up future attribution, but it's optional — you can always attribute a deposit after it arrives.
A pending attribution holds only that deposit. It doesn't block your other funds, and the address can continue receiving deposits as usual.
There's no deadline on a pending attribution and nothing clears it automatically — the deposit stays pending until someone attributes it. While anything is outstanding, we send a daily email listing what's waiting on you.
Trusted sources and deposit attribution apply to crypto deposits only. USD (fiat) deposits arrive as wire transfers and are identified by the sender's bank information — no attribution step is required.
## Trusted sources
Trusted sources allow future deposits from known addresses to be automatically attributed without manual review. Once you add an address as a trusted source, deposits from that address are attributed automatically.
### Adding a trusted source
Go to **Settings** and select **Trusted sources**, then select **Add trusted source**.
Enter the address details when prompted and confirm the information is accurate.
Select **Add trusted source**. Future deposits from this address are attributed automatically.
### Editing or removing a trusted source
Select the three-dot menu to the right of any trusted source address to edit or remove it.
If a trusted source is marked as **frozen**, reach out to your Anchorage Digital representative for assistance. A frozen source can't be used for automatic deposit attribution until the freeze is cleared.
### When to use trusted sources
* **Frequent counterparties** — Add addresses from your regular transaction partners
* **Internal transfers** — Add your own deposit addresses to skip attribution prompts
* **Institutional relationships** — Pre-add addresses from banks or other institutions you receive funds from regularly
## Deposit attribution
### Viewing and attributing pending deposits
After logging in, select **Attribute deposits** from the homepage, or navigate to the **Operations** tab.
Select the deposit you want to attribute and select **Attribute deposit**. You may attribute multiple deposits simultaneously if they share the same originator(s).
Enter the name and country of the originator. You may add multiple originators. To automatically attribute future deposits from the same address, check **Add to your trusted sources**.
Confirm the information is accurate and select **Attribute deposit**. Once attribution is complete and screening clears, the associated amount becomes available for withdrawal.
If you don't recognize a deposit, you have the option to flag it as spam.
Until you attribute the originator and screening clears, an unattributed deposit appears in your total balance but isn't available to withdraw. A received or "complete" deposit isn't the same as available funds — attribution is what releases them.
Prompt action on deposit attribution requests helps avoid withdrawal delays for deposits that can't be automatically attributed.
### Spam and dust deposits
Unsolicited deposits — spam tokens, dust amounts, or transfers from spoofed counterparties — still enter the attribution queue and are reviewed by our compliance team like any other deposit. They don't put your genuine funds at risk.
If you receive a deposit you don't recognize, leave it unattributed and don't interact with it. Flag it as spam so our team can review it.
For deposits designed to imitate addresses you already use, see [address poisoning protection](/knowledge-base/platform/users/receiving-assets#address-poisoning-protection).
### Correcting an attribution
Attribution isn't reversible from the app or the web dashboard. If you attribute a deposit to the wrong originator, or flag a genuine deposit as spam by mistake, contact your client experience team or email [accountexecutive@anchorage.com](mailto:accountexecutive@anchorage.com) with the transaction ID and the correct details. We can amend the attribution or restore a deposit that was flagged in error.
Because a correction takes a round trip, it's worth confirming the originator before you submit — particularly when you're working through a batch of deposits at once.
### Large token distributions
A vesting unlock or token distribution can arrive as many separate deposits, each landing in the attribution queue. Attributing them one at a time is slow, so add the distributing address as a trusted source: once it's added, deposits from that address are attributed automatically and the queue clears itself.
You can also attribute several pending deposits together when they share the same originator, as described above.
### Best practices
* **Verify sender information** — Confirm the originator name and country match your expected counterparties
* **Use trusted sources** — Add frequently-used addresses to trusted sources to streamline future deposits
* **Review regularly** — Check for pending attributions regularly to avoid delays in withdrawal availability
# Unsupported assets and wrong networks
Source: https://docs.anchorage.com/knowledge-base/platform/users/unsupported-assets
Understand why a deposit isn't showing and how recovery works for unsupported assets.
If an asset isn't supported, or was sent on the wrong network, it won't show a balance because Anchorage Digital doesn't scan for it. This guide explains why, and how recovery works.
## Why a deposit isn't showing
If an asset isn't supported or enabled for your organization, Anchorage Digital doesn't scan the blockchain for it, so no balance appears. This is different from a pending-attribution hold, where the deposit does show but the funds are held until you attribute the sender. See [Deposit attribution](/knowledge-base/platform/users/receiving-assets#deposit-attribution).
## Recovering an unsupported or wrong-network deposit
Share the receiving address and the on-chain transaction link with your client experience team so the asset team can investigate.
If the asset isn't supported, the asset team may be able to temporarily enable it and rescan to surface the balance, then return the funds to the sender. Outcomes depend on the asset and network.
Some deposits—especially assets sent on the wrong network or unsupported variants—may be unrecoverable. Confirm both the asset and the network before sending.
To have an asset or network supported going forward, see [Requesting asset support](/knowledge-base/platform/users/asset-support-requests).
# USD banking
Source: https://docs.anchorage.com/knowledge-base/platform/users/usd-banking
Manage USD deposits, withdrawals, interest, and account structures.
Anchorage Digital supports USD as its fiat currency, with deposits, withdrawals, interest on USD holdings, and account structuring for end clients all managed through the platform.
The platform integrates banking partners — including BNY and Customers Bank — to support deposits, withdrawals, and interest generation.
Each vault can hold one USD wallet. Unlike crypto wallets, which can have multiple wallets per asset within a vault, USD is limited to a single wallet per vault. This distinction shapes how you structure accounts — especially for organizations serving their own end clients.
All USD operations are reflected in your standard reporting tools:
* Real-time **Activity feed** in the web dashboard
* Monthly downloadable **Statements** for accounting and reconciliation
* Custom **User-generated reports**
* Programmatic **Webhooks**
Create a USD wallet, access wire instructions, and receive USD deposits.
Add USD trusted destinations and send wire transfers.
Enroll in the USD Interest Program and earn interest on holdings.
Structure vaults and wallets to serve your own end clients.
## USD rails
Wire transfer is the rail for moving USD in and out of Anchorage Digital today. Here's where each rail stands:
Wire transfers
ACH—reach out to your relationship manager for beta access
RTP and FedNow
# USD deposits
Source: https://docs.anchorage.com/knowledge-base/platform/users/usd-deposits
Create a USD wallet, access wire instructions, and receive USD deposits.
To receive a USD deposit, you need a USD wallet with wire instructions that you can share with the sending party. Wire transfer is the only generally available deposit rail—for where ACH and other rails stand, see [USD rails](/knowledge-base/platform/users/usd-banking#usd-rails).
## Creating a USD wallet
Go to the desired vault, select **Deposit**, then select **USD** as the asset type. If a USD wallet doesn't already exist, this creates one with unique wire instructions.
This operation is immediate and doesn't require quorum or Anchorage Digital approval.
You can only create one USD wallet per vault.
## Accessing wire instructions
You can access wire instructions from the iOS app or web dashboard.
Go to the desired vault, select **Deposit**, and select **USD** to view the vault's wire instructions.
Don't have senders push ACH deposits to your USD wallet's account details—only wire transfers are accepted.
An incoming FedWire posts an IMAD reference in your activity roughly 15–30 minutes after the sending bank releases it. Use the IMAD to reconcile the deposit.
## After enrolling in the USD Interest Program
Once enrolled in the [USD Interest Program](/knowledge-base/platform/users/usd-interest):
* **Primary bank**: BNY serves as the primary bank for deposits and withdrawals. Your USD wallet deposit instructions update dynamically to reflect BNY details.
* **International wires (SWIFT)**: BNY is a SWIFT member, so you can send and receive international wires over SWIFT without an intermediary bank.
* **Domestic wires**: Deposit instructions for BNY don't require a domestic intermediary bank.
Previous deposit instructions continue to operate even if they're not displayed in your wallet's deposit instructions.
# USD interest
Source: https://docs.anchorage.com/knowledge-base/platform/users/usd-interest
Enroll in the USD Interest Program and earn interest on USD holdings.
Anchorage Digital offers the ability to earn interest on USD holdings held on the platform.
## Eligibility and enrollment
Accounts created after February 26, 2026 are automatically enrolled in the USD Interest Program.
ETF and Wealth Management clients (including Exchange-Traded Funds and Registered Investment Advisors) are currently not eligible for the USD Interest Program.
To enroll manually, navigate to your USD wallet, select **Deposit**, then **Enroll now**.
Enrollment is at the account level. If you have multiple accounts, you must enroll each one separately.
Once enrolled, you'll see new USD deposit instructions in your account. If you don't want your deposit instructions to change, contact your relationship manager.
## Changes after enrolling
Once enrolled:
* **Primary custodian**: BNY serves as the primary bank for deposits and withdrawals. Your USD wallet deposit instructions update dynamically to reflect BNY details.
* **International wires (SWIFT)**: BNY is a SWIFT member, so you can send and receive international wires over SWIFT without an intermediary bank. Intermediary bank instructions for international USD trusted destinations are now optional, and previous country restrictions have been removed.
* **Domestic wires**: Deposit instructions for BNY don't require a domestic intermediary bank.
Previous deposit instructions continue to operate even if they're not displayed in your wallet's deposit instructions.
## Interest accrual and payouts
| Component | Description |
| ----------------- | -------------------------------------------------------------------------------- |
| Daily accrual | Interest accrues daily based on your account's wallet balances. |
| Monthly payout | Accrued interest is distributed by the 10th calendar day of the following month. |
| Transaction label | Interest appears as "Interest deposit" in your activity feed and statements. |
Interest payouts appear automatically in your standard Anchorage Digital reporting tools: Activity feed, Statements, User-generated reports, and Webhooks.
## Tax reporting
At the end of the tax year, you'll receive a 1099 tax form for interest earned on USD. One form is issued per account.
For questions about enrollment status, banking instructions, or interest payouts, contact Anchorage Digital Support or your Relationship Manager.
# USD withdrawals
Source: https://docs.anchorage.com/knowledge-base/platform/users/usd-withdrawals
Add a USD trusted destination and send USD wire transfers.
To send USD from Anchorage Digital, you first add the recipient's bank information as a trusted destination, then initiate a withdrawal from your USD wallet.
## Adding a USD trusted destination
You must be an administrator with trusted destination management permissions. You'll need your iOS device for biometric approval.
Go to **Settings** and select **Trusted destinations**.
Select **Add trusted destination**, then select **Add single (Fiat)**.
Fill in the required information for the recipient account holder.
Select **Domestic** or **International** for the bank account type. Fill in the required bank information and select **Preview**.
Review the operation and select **Confirm and submit for approval**. Complete biometric endorsement. Once the required quorum and sub-quorum approvals are submitted, Anchorage Digital will review the trusted destination.
If you enter information in the **Memo** field, it pre-populates whenever you use this trusted destination for a withdrawal. You can still edit the memo during the withdrawal.
## Sending USD
Once a trusted destination is approved, initiate a withdrawal from the iOS app or web dashboard.
Select the vault and tap **Withdraw**.
Select **USD** as the asset type and **Trusted Destination** as the destination type. Choose the trusted destination you want to send funds to.
Enter the USD withdrawal amount. The **Add memo** field is optional and is pre-populated if a memo was included when the trusted destination was created.
Review the withdrawal and select **Confirm and endorse withdrawal**. Vault members included in your withdrawal policy will receive a notification to approve the withdrawal.
Once the required quorum and sub-quorum approvals are submitted, Anchorage Digital will review the withdrawal for approval.
For same-day wire withdrawals, the daily cut-off time is 5:00 PM ET for BNY and Customers Bank, and 3:00 PM ET for Cross River Bank. Any requests submitted after these times will be processed on a best-effort basis. To confirm which bank your account routes through, check your wire instructions or contact your relationship manager.
# Use these docs with AI
Source: https://docs.anchorage.com/knowledge-base/platform/users/using-ai
Ask AI about Anchorage Digital, open any page in your assistant, or give your tools the whole knowledge base.
You don't have to be a developer to use AI with these docs. Ask questions in plain language, open any page in your AI assistant, or give your assistant—or a tool like Slack—the entire Anchorage Digital knowledge base to answer from.
## Ask AI on any page
Every page has an AI menu at the top right. Use it to:
* **Ask Assistant** — ask questions about the page you're reading, without leaving the docs.
* **Open in Claude**, **ChatGPT**, **Perplexity**, or **Google AI Studio** — continue in your assistant with the page as context.
* **Copy page** — copy the page as text to paste anywhere.
## Give your AI assistant the whole knowledge base
Connect our documentation server so your AI assistant can search and cite Anchorage Digital docs on demand. This works with any assistant that supports custom connectors, including ones your team uses in Slack.
Add this server URL in your assistant's connector settings:
```text theme={null}
https://docs.anchorage.com/mcp
```
To include documentation restricted to your account, use `https://docs.anchorage.com/authed/mcp` and sign in when prompted.
For step-by-step setup for each tool, see [Connect your AI assistant](/knowledge-base/build-with-ai/connect-ai-assistant).
## Download the full knowledge base
To feed the docs into another tool or share them with your team, get the whole site as a single file:
```text theme={null}
https://docs.anchorage.com/llms-full.txt
```
You can also add `.md` to any page URL to get just that page as text.
This connects your assistant to documentation only. It's read-only and can't access your account or balances, or move assets on your behalf—use the Anchorage Digital app for those actions.
## Building an integration?
If you're writing code against the Anchorage Digital API, see [Build with AI](/knowledge-base/build-with-ai/overview) for MCP setup, ready-made prompts, and security guardrails.
# Vault policies
Source: https://docs.anchorage.com/knowledge-base/platform/users/vault-policies
Customize quorum and sub-quorum settings for vault operations.
All operations in a vault follow the default policy unless you customize settings per operation type: governance, staking, or withdrawal.
You can create a single vault policy and assign it to multiple vaults. Any update to that policy applies to every assigned vault — no need to make the same change vault by vault. For vaults that require a unique configuration, you can create a policy tailored to that vault.
For each vault policy, administrators with vault management permissions can: (1) change base quorum members, (2) edit the base quorum approval limit, (3) add or delete sub-quorums, (4) change sub-quorum members, (5) edit sub-quorum approval limits, or (6) update its **Assigned vaults**.
Any changes to vault policies are subject to quorum approval per the default administrator policy or vault management policy (if one is configured). You will be prompted to submit biometric approval on your iOS device.
Tap **Settings**, then **Policies**, and select the vault policy you want to customize.
A vault policy's base rule can also resolve to **Block** instead of quorum, which rejects every operation of that type for all vaults the policy is assigned to. Pair a conditional rule above it — for example, allowing withdrawals to trusted destinations — to let specific cases through while blocking everything else. Block isn't available on the administrator policy. See [Outcomes](/knowledge-base/platform/users/rules#outcomes) for how the two outcomes differ.
## Quorum members
The base quorum defines the pool of members eligible to approve operations under a vault policy.
### Editing quorum members
Tap **Rules**, then tap the three-dot menu next to the rule you want to edit and select **Edit rule**.
In **Edit rule**, tap the **Quorum is** field, select the members who can approve operations under this rule, and tap **Continue**.
Tap **Done** to save the rule. Follow the prompts to submit biometric approval — quorum approval is required.
## Base quorum approvals
The approval limit defines how many base quorum members must approve an operation before it can proceed.
### Editing quorum approvals
Tap **Rules**, then tap the three-dot menu next to the rule you want to edit and select **Edit rule**.
In **Edit rule**, use the stepper under **Number of approvals required** to set how many quorum members must approve.
Tap **Done** to save the rule. Follow the prompts to submit biometric approval — quorum approval is required.
## Sub-quorums
Sub-quorums add an additional layer of approval security. Each sub-quorum establishes a prerequisite: an operation cannot be completed without a preset number of approvals from the designated sub-quorum members.
Administrators with vault management permissions can add as many sub-quorums as needed for each vault policy.
### Adding a sub-quorum
Tap **Rules**, then tap the three-dot menu next to the rule you want to edit and select **Edit rule**.
In **Edit rule**, tap **Add sub-quorum**.
From the base quorum's approver pool, select at least one member for the sub-quorum and tap **Continue**.
Set the number of approvals this sub-quorum requires and tap **Continue**.
Give the sub-quorum a name and an optional description, then tap **Finish**.
Back in **Edit rule**, confirm the new sub-quorum, then tap **Done**. Follow the prompts to submit biometric approval — quorum approval is required.
### Editing sub-quorum details
Administrators with vault management permissions may update a sub-quorum's name and description if circumstances change.
Tap **Rules**, then tap the three-dot menu next to the rule you want to edit and select **Edit rule**.
Tap the three-dot menu next to the sub-quorum you want to edit and select **Edit details**.
Update the **Sub-quorum name** or description as needed, then tap **Finish**.
Back in **Edit rule**, tap **Done**. Follow the prompts to submit biometric approval — quorum approval is required.
### Editing sub-quorum members
Tap **Rules**, then tap the three-dot menu next to the rule you want to edit and select **Edit rule**.
Tap the three-dot menu next to the sub-quorum, select **Edit members**, then update the selected members and tap **Continue**.
Back in **Edit rule**, tap **Done**. Follow the prompts to submit biometric approval — quorum approval is required.
### Editing sub-quorum approvals
Tap **Rules**, then tap the three-dot menu next to the rule you want to edit and select **Edit rule**.
Tap the three-dot menu next to the sub-quorum, select **Edit approval limit**, choose the number of required approvers, and tap **Save**.
Back in **Edit rule**, tap **Done**. Follow the prompts to submit biometric approval — quorum approval is required.
### Deleting a sub-quorum
Tap **Rules**, then tap the three-dot menu next to the rule you want to edit and select **Edit rule**.
Tap the three-dot menu next to the sub-quorum and select **Delete**.
Back in **Edit rule**, tap **Done**. Follow the prompts to submit biometric approval — quorum approval is required.
## Reset to default policy
You can reset a customized vault policy back to the default configuration at any time.
Tap **Vault policies** on the vault settings menu and select the policy you want to reset.
Select **Reset to default policy** and follow the prompts.
Select **Reset to default policy** again and confirm that you want to reset.
Tap **Finish and review** and follow the prompts to submit biometric approval — quorum approval is required.
# Vaults & wallets overview
Source: https://docs.anchorage.com/knowledge-base/platform/users/vaults-wallets
Understand the organization, vault, wallet, and address hierarchy.
## Overview
Assets on the platform are organized in a four-level hierarchy: **organization → vaults → wallets → addresses**. Your organization is at the top — it holds your users, policies, and all vaults beneath it.
Your institution's account. It owns all users, policies, and vaults, and defines who can do what across the platform.
Multi-asset containers with customizable policies, quorums, and user permissions. Each vault operates independently with its own approval rules.
Inside a vault, each asset is stored within a wallet. Multiple wallets of the same asset can exist within a vault — useful for segregating assets by counterparty.
Each wallet can have one or more addresses. For UTXO networks like Bitcoin, multiple addresses can be created — all pooled to the same wallet. For account-based networks like Ethereum, the wallet address is unique.
### Crypto vs. USD wallets
Crypto and USD wallets share the same vault structure but behave differently:
* **Crypto wallets** — you can create multiple wallets for the same asset within a vault, each with its own deposit address. This is useful for segregating assets by counterparty or purpose. See [Wallet creation](/knowledge-base/platform/users/wallet-creation) for options.
* **USD wallets** — each vault holds at most one USD wallet with unique wire instructions. USD deposits arrive as wire transfers identified by sender bank information, not wallet addresses. See [USD banking](/knowledge-base/platform/users/usd-banking) for details.
### Structuring vaults by client or strategy
To keep each client or strategy separate, create a dedicated vault for it — see [Creating vaults](/knowledge-base/platform/users/creating-vaults). Wallets created in that vault get their own deposit addresses, so funds stay segregated and addresses aren't accidentally reused across clients.
When you create a wallet, you also control whether its address is shared with compatible networks. See [Wallet creation](/knowledge-base/platform/users/wallet-creation) for the address-sharing options.
# Understanding wallets and addresses
Source: https://docs.anchorage.com/knowledge-base/platform/users/wallet-address-model
Understand how wallets map to on-chain addresses and what a single address can hold.
A wallet at Anchorage Digital isn't necessarily an on-chain address. Sometimes the two line up one to one, sometimes one wallet pools many addresses, and sometimes several wallets sit behind a single address. Knowing which case you're in tells you how many addresses you'll be handing out and how your balances are organized.
It helps to keep two ideas apart. An **on-chain wallet** is a keypair and the address derived from it, and it works on every network that shares its key derivation. An **Anchorage Digital wallet** is where your balances for one network live inside a vault, with its own wallet ID, name, and archive state. For how vaults and wallets fit together, see [Vaults and wallets overview](/knowledge-base/platform/users/vaults-wallets).
## How a wallet maps to addresses
Every wallet has one wallet ID, and that's what the platform works with. Withdrawals and balances always name a wallet. The number of on-chain addresses underneath it depends on the network.
On networks like Ethereum, your wallet has a single address and the two are easy to think of as the same thing. On Bitcoin they aren't: you can generate as many addresses as you like, every one of them receives, and they all pool into one balance. Anchorage Digital also adds change addresses for you when you transfer, and those count toward the same balance.
## What one address can hold
A single address holds more than one type of asset. On Ethereum, ETH and every token issued on Ethereum arrive at the same address and sit in the same wallet, each with its own balance.
This is why you can't add a second deposit address to an existing Ethereum wallet. If you want a separate address, create another wallet in the vault and it gets its own. See [Creating and managing wallets](/knowledge-base/platform/users/wallet-creation).
## Two ways to set up compatible networks
Some networks are close enough relatives that one keypair works across all of them. Anchorage Digital supports this on EVM, SPL, and Tendermint networks, and calls them compatible networks. When you create wallets on more than one network in the same family, you have a choice to make.
You make this choice when you create the wallet, and you can extend an existing wallet's address onto more compatible networks later. [Creating and managing wallets](/knowledge-base/platform/users/wallet-creation) walks through both flows.
Sharing an address doesn't share a balance. To move assets from one compatible network to another, they have to be bridged.
## Try a configuration
Pick a network, decide how many networks you want to cover, and choose an address strategy. The diagram updates to show the wallets you'd create and the addresses underneath them.
## Good to know
* The first wallet you create for a network in a vault becomes that vault's default wallet, which is the source of funds for external withdrawals.
* Addresses can't be deleted once generated, because they stay live on the blockchain and can keep receiving deposits.
* Trusted destinations are per network, so the same address on two networks needs two separate entries. See [Trusted destinations](/knowledge-base/platform/users/trusted-destinations).
* On some networks, creating one wallet also creates the wallets for every compatible network and archives them to keep your dashboard tidy. Archived wallets still receive deposits, but unarchive them before staking or withdrawing.
* If a deposit lands on a compatible network where you don't have a wallet yet, we'll create one for you once the deposit clears spam attribution.
* For what each balance label means, see [Reading balances](/knowledge-base/platform/users/reading-balances).
# Creating and managing wallets
Source: https://docs.anchorage.com/knowledge-base/platform/users/wallet-creation
Create, view, and archive wallets, and understand how deposit addresses work.
When you create a new wallet on a network that supports address sharing (EVM, SPL, and Tendermint networks), you can choose whether to use the address on a single network, all compatible networks, or a selected subset.
Existing wallets are not affected by this flow. Wallets created before this update are preserved and continue to work as before.
## Accessing wallet details
From the wallet details page, you can:
* Check wallet balances and holdings
* Generate additional wallet addresses (if applicable)
* Initiate withdrawals
* Check the deposit address and pooled wallet addresses (if applicable)
* Edit the wallet name
**On iOS**: On the vault page, select the asset to see the associated wallets in the vault. Tap the wallet to see its details.
**On web dashboard**: On the vault page, navigate to the **Wallet** tab and click on a wallet to see its details. Wallet details include balances, tokens associated with that address (e.g., ERC-20 tokens), staked balances, and other asset-specific information such as pooled addresses (BTC assets) or bank account information (USD wallets).
## Creating a new wallet
Unlike creating a vault, creating a wallet in an existing vault doesn't require quorum approval.
### On the web dashboard
Click **Create wallet**.
Select the network and click **Continue**.
If the selected network supports address sharing, choose how you want to use the address:
* **Use address for selected network only** (default) — Creates a wallet with a unique address on the selected network. No other networks are affected.
* **Use address for all compatible networks** — Creates the same wallet address across every compatible network Anchorage Digital supports. One shared address, multiple wallets.
* **Use address only for selected compatible networks** — Creates the same wallet address on a subset of networks you choose.
Click **Continue**.
Optionally give the new wallet or wallets a name, then select **Create wallet**. Your new wallet is ready for deposits and withdrawals and will appear in the table sorted by creation date.
### On iOS
On the vault page, tap the asset, then tap the icon to create a new wallet and follow the prompts.
For wallets on address-sharing networks, select how you want to use the address:
* **Use address for \[network] only** (default) — Creates a wallet with a unique address on the selected network. No other networks are affected.
* **Use address for all compatible networks** — Creates the same wallet address across every compatible network Anchorage Digital supports.
* **Use address only for selected compatible networks** — Creates the same wallet address on a subset of networks you choose.
Tap **Continue** to create the wallet.
## Creating a new wallet address
Additional addresses are available on UTXO-based networks (e.g., Bitcoin). All addresses are pooled to the same wallet.
Tap the desired wallet, then tap **Deposit**. To view additional addresses, tap **Show all**, then **Generate new** to create a new address.
Additional or pooled wallet addresses are only available on UTXO-based networks.
## One address per wallet on account-based networks
On account-based networks like Ethereum, each wallet has a single address, and every token on that network shares it—ETH and all ERC-20 tokens in the wallet use the same deposit address. You can't add more addresses to the wallet itself; additional addresses are only available on UTXO-based networks, as described above.
To get a separate deposit address on an account-based network, create another wallet in the vault—see [Creating a new wallet](#creating-a-new-wallet).
## Bulk wallet creation
On the web dashboard, you can create up to 25 new addresses at once with the **Create Wallet** flow. Select how many new addresses you'd like to create, then proceed to select sharing options and continue.
## Adding new networks to an existing wallet
You can extend an existing wallet's address onto additional compatible networks at any time. This applies to wallets on EVM, SPL, and Tendermint networks.
### On the web dashboard
On the vault page, click the wallet to open its details.
Click the **Network** dropdown and select **Add network**.
Select one or more compatible networks from the list, then click **Create**. The new networks appear under the dropdown once the wallets are created. Each network shares the same address but maintains its own balances and assets.
### On iOS
Navigate to the wallet details page and tap the more menu. Select **Add network**, select one or more compatible networks to enable, and confirm.
## Automatic deposit detection
Deposits to a shared address are detected automatically, even on networks where you haven't yet created a wallet.
When a deposit arrives on a compatible network where the address already exists for another network, Anchorage Digital:
1. Detects the balance on the shared address.
2. Runs spam attribution on the deposit.
3. Creates a wallet on the new network using the shared address, if the deposit is not attributed as spam.
4. Displays the incoming deposit in the newly created wallet, visible on the Operations page.
The new network appears in the **Network** dropdown on the wallet details page with its balance visible. System-created wallets are labeled to distinguish them from wallets you created yourself.
Spam deposits don't generate new wallets. Auto-creation only occurs after a deposit clears spam attribution. If a deposit is erroneously marked as spam, contact your account executive at [accountexecutive@anchorage.com](mailto:accountexecutive@anchorage.com).
## Archiving and unarchiving wallets
Archiving a wallet keeps your active list focused without deleting the wallet. You can unarchive it anytime you need access again.
### Archive a wallet
Select the vault holding the wallet you want to archive, then go to the **Wallets** tab.
Next to **Create wallet**, select the **Wallet archive** icon to open the **Archive wallets** window.
From the **Active** tab, select the wallets you'd like to archive, then select **Archive wallets**.
### Unarchive a wallet
Select the vault holding the wallet you want to unarchive, then go to the **Wallets** tab.
Next to **Create wallet**, select the **Wallet archive** icon to open the **Archive wallets** window.
From the **Archived** tab, select the wallets you'd like to unarchive, then select **Unarchive wallets**.
Unarchive a wallet before performing operations like staking and withdrawing on it — archived wallets can't be used for these operations.
# Cost basis FAQ
Source: https://docs.anchorage.com/knowledge-base/platform/users/web-dashboard/cost-basis-faq
Answer common questions about cost basis, tax lots, and how asset types are taxed.
Answers to common questions about cost basis, tax lots, and how different asset types are treated in your tax reports. For instructions on submitting cost basis data, see [Cost basis](/knowledge-base/platform/users/web-dashboard/tax-center#cost-basis).
Anchorage Digital does not provide financial, tax, or legal advice. Consult a qualified professional for guidance specific to your situation.
The original value of an asset at the time you acquired it, including any fees paid as part of the acquisition. It's used to calculate capital gains or losses when you sell, trade, or dispose of the asset.
When you deposit assets from an external source, we don't have visibility into when or at what price you acquired them. Providing this information helps ensure your tax reports are accurate. The cost basis you provide may be used in tax forms such as 1099-DA, for eligible US tax-paying entities — see the next question for what's covered.
Covered assets are crypto assets acquired on or after January 1, 2026, and held at Anchorage Digital until sold. For these, we report both gross proceeds and cost basis to you and the IRS on Form 1099-DA — review your 1099-DA to confirm the cost basis is accurate.
Noncovered assets are crypto assets acquired before January 1, 2026, or deposited from an external source. For these, we report gross proceeds but not cost basis to the IRS. If you provide cost basis for your deposits, we include it in the information we share with you, but you're responsible for reporting it to the IRS on your tax returns.
It depends on how you originally acquired the assets. Common sources include:
* Transaction history or tax reports from the original exchange or platform
* Blockchain records for on-chain acquisitions
* Brokerage or custody statements, or trade confirmations from OTC desks
* Records from your tax advisor or accounting software
If you're unsure where to find cost basis for your assets, we suggest confirming this detail with your Finance or Tax team.
A record of a specific acquisition, including quantity, date, and cost basis. A single deposit can have multiple tax lots if portions were acquired at different times or prices.
A cost basis method determines which tax lots are sold first when you dispose of an asset. Anchorage Digital supports:
* **FIFO (First-In, First-Out)** — Oldest lots are sold first.
* **HIFO (Highest-In, First-Out)** — Highest cost basis lots are sold first. This is the default method.
* **LIFO (Last-In, First-Out)** — Most recent lots are sold first.
* **LOFO (Lowest-In, First-Out)** — Lowest cost basis lots are sold first.
Contact your account team to change your cost basis method.
No. Anchorage Digital already has the acquisition data for assets purchased, traded, or received as rewards on the platform. Cost basis is only required for deposits from external sources.
Staking rewards are generally treated as income at the fair market value when received. That value becomes the cost basis for the asset. You don't need to provide cost basis for rewards earned on Anchorage Digital.
Stablecoin rewards follow the same principle: they're treated as income at fair market value when received, which becomes their cost basis. For fiat-pegged stablecoins, fair market value is typically near the peg (e.g., about \$1.00 for USD stablecoins), subject to market deviations.
If you don't provide cost basis, the system defaults to a \$0 cost basis and uses the deposit date and time as the acquisition date. This may result in overstated gains or inaccurate tax reports. We recommend providing cost basis for all deposits as soon as possible after they're completed.
## Related topics
* [Tax center](/knowledge-base/platform/users/web-dashboard/tax-center#cost-basis) — Supply cost basis information, manage tax documents, and certify tax information
* [Reporting](/knowledge-base/platform/users/web-dashboard/reporting) — View statements and download balance and transaction reports
# Developers
Source: https://docs.anchorage.com/knowledge-base/platform/users/web-dashboard/developers
Access APIs, create permission groups, and generate API keys from the Anchorage Digital web dashboard.
This guide is for web dashboard users who want to connect their own tools to Anchorage Digital through the API. Anchorage Digital APIs let you integrate your own tools with the Anchorage Digital platform. API keys are configured through the web dashboard and only administrators can create them. Each key is assigned to a permission group that authorizes the holder to perform the granted permissions.
Here's what an API integration can do for your organization:
* **Easy reporting** — Generate reports, build financial dashboards, and view all digital assets in custody.
* **Automated tracking** — Download crypto and [USD](/knowledge-base/platform/users/usd-banking) (fiat) balances, including all transactions across the organization's vaults, and store data for processing and reconciliation.
* **Complete monitoring** — Read and monitor vault balances, query transaction history including deposits, and get visibility on trading activity.
## Accessing developer settings
On the web dashboard homepage, select **Developers** on the sidebar to access developer settings.
## Creating a permission group
Permission groups contain a set of allowable permissions that can be assigned to one or more API keys. Only administrators can create and manage permission groups.
In the web dashboard, select **Create new group**.
Give the permission group a name, then select the appropriate permissions from the list of global and vault-level permissions.
Add a comment (optional), select **Endorse to create a group**, and complete biometric authentication via the mobile app. After quorum is met, Anchorage Digital will review for approval.
## Creating an API key
In the API section of the web dashboard, select **Create API key**.
Enter the key name, select the permission group, and if applicable, enter a contact email and the public key.
Select **Create key**. Generating an API key triggers an email confirmation — check your email to confirm the key was created.
Selecting certain permission groups requires additional approval when creating a key.
## Edit, revoke, and delete
To revoke an API key, select **Revoke** next to the key details.
To edit or delete a permission group, select the three dots next to the group details. Changes to permission groups require endorsement via the iOS app.
## Continue in the developer docs
Once you have an API key, the developer documentation covers how to authenticate and build against the Anchorage Digital API.
Set up your API integration, from permission groups to your first authenticated request.
Sign sensitive API requests with your Ed25519 key so they pass authorization.
Test your integration in a safe environment before moving to production.
Subscribe to events to track balances, transactions, and status changes in real time.
For deeper integration guides, see [permission groups](/knowledge-base/platform/developers/permission-groups), [API keys](/knowledge-base/platform/developers/api-keys), [move money](/knowledge-base/platform/developers/move-money/overview), and the [developer FAQs](/knowledge-base/platform/developers/faqs).
# Invoices
Source: https://docs.anchorage.com/knowledge-base/platform/users/web-dashboard/invoices
View, download, and pay your Anchorage Digital invoices, and manage invoice delivery preferences.
In **Settings**, under **Billing hub**, select **Invoices** to view, download, and share invoices. You can also manage invoice delivery preferences to add people to the permanent invoice distribution list.
## Invoices FAQs
Find answers to common questions about viewing, paying, and managing your Anchorage Digital invoices, including payment methods, fee calculations, and how to update your billing details.
### Paying your invoice
Invoices can be settled by wire, ACH, or stablecoin, and can be paid directly through the Stripe payment link on your invoice. We also support auto-pay. For stablecoin payments, reach out to the Anchorage Digital billing team to find out which asset types are supported and the appropriate wallet destination. Where wire fees are charged, a standard wire fee schedule applies—your billing contact can share it.
We've integrated Stripe to make paying your invoices faster, simpler, and more secure. Every invoice PDF now includes a direct payment link, giving you a streamlined and flexible checkout experience.
Why use the payment link?
* **Convenience:** Pay directly from your invoice PDF.
* **Automated management:** Save your payment method or enroll in auto-pay to skip manual entry each month.
* **Rapid reconciliation:** Unique links ensure your payments are recognized instantly, preventing redundant past-due reminders.
**Note:** Every payment link is authentic, secure, and unique to your account. We highly recommend using this method to streamline your monthly payments.
You may call our billing support line at +1 (415) 909-3517 to confirm banking instructions.
Unfortunately, we are not able to sign up for third-party payment systems.
We accept payments via ACH, wire, or stablecoins. Please reference our international wire instructions to process payment. Payment can also be made via the direct link on the invoices sent out by Anchorage Digital.
Anchorage Digital is unable to connect directly through **Bill.com**; however, you can still pay us through **Bill.com** using the following steps:
1. Select **Vendors** in the navigation menu.
2. Select the vendor's name.
3. Select **Edit**.
4. Select **Payment type** to expand that section.
5. Select **Bank Deposit - pay with your vendor's banking information**.
6. Enter the vendor's bank account information:
* Routing number
* Account number
* Re-enter account number
* Account holder name
7. Select **Save**.
The bank account immediately shows that it's a verified status.
In 1-2 business days, we'll send a test deposit of \$0.01 (one cent) to your vendor's bank account to confirm it's able to receive payments, and this won't be re-debited.
For the first payment after manually adding a vendor's bank account, the earliest process date that can be selected is 2 business days after the date the bank was added. This is to ensure the test deposit completes successfully. We'll also send an email notification to your vendor that you've added their bank information for payments.
No, we do not accept credit cards as a form of payment. To ensure secure and efficient processing, we accept the following payment methods:
* Stripe auto-pay
* ACH / direct deposit
* Wire transfer
* Stablecoins
No, we do not support advance prepayments. All accounts are billed monthly.
However, we've streamlined our monthly payment process, which is powered by Stripe. When you receive your monthly invoices, you can click the direct link to:
* Save your payment method for faster manual checkout.
* Enroll in auto-pay to handle your monthly invoices automatically.
No, automatic recurring payments cannot be initiated from on-platform vaults.
Our vault security protocols require your explicit, manual authorization for every transaction to ensure total control of your assets. Because vault funds cannot be automatically withdrawn, you will need to manually initiate your payment each month.
### Understanding your invoice
This invoice is generated in accordance with your signed **Master Services Agreement (MSA)**. Per our contract terms, service fees and monthly commitments begin accruing automatically on the contract's effective date.
Custody fees are tiered basis-point rates on your assets under custody, with a monthly minimum. Rates fall as assets under custody rise, and your invoice reflects those tiers. For a detailed breakdown of how your fee was calculated, reach out to your billing contact.
If your finance team needs a copy of your signed agreement for reference, please contact us at **[billing@anchorage.com](mailto:billing@anchorage.com)** and we will gladly provide it.
The Assessed Value represents the assets under custody, determined by the average daily balance of all digital assets in Anchorage Digital's custody throughout the month.
Calculation breakdown:
* **Daily valuation:** Daily asset balances are measured at 11:59 PM (23:59) UTC using market pricing data from CryptoCompare.com.
* **Monthly average:** We sum the daily balances of all assets and divide by the number of days in the month.
* **Fee calculation:** Your fee is calculated using this monthly average and billed at the end of the month.
**Note:** If your monthly calculated fee is less than your account's contractual minimum fee, the minimum fee will apply.
To calculate your invoice totals against account balances:
Download your daily balances:
* Log into the web dashboard.
* Select the **Reports** tab.
* Select the time frame you want to pull daily balances for.
* Select **CSV** to create a file of all daily balances for that period.
Calculate your custody fee:
* Sum the daily balances from the downloaded report and divide by the number of days in the month to get your average balance.
* Refer to the fee table in your contract to find the annualized fee rate for your average balance.
* Multiply the average balance by the annualized fee rate divided by 12 to get your monthly custody fee.
If you believe there is an error on your invoice or need to request a credit memo, please reach out to our billing team directly at **[billing@anchorage.com](mailto:billing@anchorage.com)**.
To help us resolve this for you as quickly as possible, please include the following details in your message:
* Your company name
* The specific invoice number(s) in question
* A brief explanation of the discrepancy or the reason for the credit request
Once submitted, our billing team will review your request and get back to you within 1-2 business days.
You can retrieve copies of your invoices at any time by following these steps:
1. Log into your web dashboard.
2. Select **Invoices** under **Billing hub** in **Settings**.
3. Select your desired invoice and select **Download** inside the **more options menu** in that invoice's row.
You can update your invoice email distribution list at any time by following these steps:
1. Log into your web dashboard.
2. Select **Invoices** under **Billing hub** in **Settings**.
3. Select **Manage invoice delivery** in the **more options menu**.
4. Enter your updated invoice email contacts and select **Save**.
We'd be happy to update your billing address for all future invoices.
Please send us your new details to **[billing@anchorage.com](mailto:billing@anchorage.com)** and our team will update your account promptly.
**Note:** Changes will apply to future invoices only. Due to system constraints, we're unable to modify or reissue past invoices that have already been generated.
We typically aim to issue invoices by the **8th business day** following month-end. Invoices will be available to view and download in your web dashboard within 24 hours of being issued.
### Miscellaneous questions
To request account closure, please email our team at **[accountexecutive@anchorage.com](mailto:accountexecutive@anchorage.com)**.
**Note:** Please be aware that accounts can only be officially closed once all outstanding invoices and balance fees have been paid in full.
Send your audit confirmation request to **[cxm-com@anchorlabs.com](mailto:cxm-com@anchorlabs.com)** with the following details:
* Your legal entity name
* The relevant invoice numbers
* The specific audit period
Our Client Experience team will verify the details and send the confirmation directly to your team or your independent auditors.
We're here to help! If you have additional billing questions or need further assistance, please reach out to our team directly at **[billing@anchorage.com](mailto:billing@anchorage.com)**, and we will get back to you promptly.
# Operation tagging
Source: https://docs.anchorage.com/knowledge-base/platform/users/web-dashboard/operation-tagging
Create and apply tags to operations, filter the Operations tab by tag, and build tag-filtered reports.
Tags let your organization label operations with your own categories—for example, by desk, strategy, or client—so they're easier to find, filter, and report on later. You can add tags when you initiate an operation or at any time afterward, and each operation can carry up to 10 tags.
## Adding tags when initiating an operation
Tags are added on the **Preview operation** screen, after you've entered the operation details.
Initiate the operation and enter its details as usual. On the **Preview operation** screen, find the **Tags** section and its **Add tags** bar.
Select the **Add tags** bar to open your organization's library of existing tags. Search for and select the tags you want to apply.
To create a tag that doesn't exist yet, type its name in the search field, then select **Create** or press Enter.
Select the **x** on a tag pill in the bar to remove it.
Select **Confirm and submit for approval**. Everyone in the approval quorum sees the applied tags when reviewing the operation.
## Viewing and editing tags on an existing operation
Select an operation in the **Operations** tab to open its details panel and see the tags applied to it. From there, you can add more tags from the **Tags** bar or remove tags by selecting the **x** on a tag pill—the same way as during initiation, with the same 10-tag maximum.
Changes to tags save to the operation automatically as you add or remove them.
## Filtering operations by tag
Navigate to the **Operations** tab.
Select **Add filter**, then **Tags**.
Select one or more tags. The table updates to show matching operations, and the active filter appears as a pill above the table.
Selecting multiple tags shows every operation that carries any of the selected tags—an operation only needs to match one of them to appear. To remove filters, select the **x** on a filter pill or select **Clear all filters**.
## Creating a report filtered by tag
You can use tags as a filter when building a transaction report in the [Reporting](/knowledge-base/platform/users/web-dashboard/reporting) section.
Go to the **Reporting** section and select **Create new report**.
Select **Transaction Report** as the report type, then enter your desired inputs, such as the report name, format, and date range.
Select **Add filter**, then **Tags**, and select the tags you want the report to cover. As with operation filtering, multiple tags match operations that carry any of the selected tags.
Select **Create report**. The generated report includes a **Tag Names** column listing the tags that apply to each transaction.
## Related topics
* [Operations](/knowledge-base/platform/users/web-dashboard/operations) — View, filter, and download pending and past account operations
* [Reporting](/knowledge-base/platform/users/web-dashboard/reporting) — View statements and download balance and transaction reports
# Operations
Source: https://docs.anchorage.com/knowledge-base/platform/users/web-dashboard/operations
View, filter, and download pending and past account operations.
The Anchorage Digital web dashboard provides tools for reviewing your organization's transaction history.
## Operations
Navigate to the **Operations** tab to view, filter, and download pending and past account operations. You can search by transaction type, date range, or status to find specific transactions. The Operations tab also serves as your audit trail of operations across the organization.
Operations rejected by a policy rule with a **Block** [outcome](/knowledge-base/platform/users/rules#outcomes) are recorded here too, even though they never reach approval. You'll only see the blocked operations you initiated yourself — they aren't visible to the rest of your organization. Governance operations and withdrawals initiated through the API are the exception.
For programmatic access to money movement, use the API—see [Track operation status](/knowledge-base/platform/developers/move-money/operate/track-status).
If past operations won't load, refresh the page with SHIFT held down (a hard reload) to clear the stale view.
## Related topics
* [Operation tagging](/knowledge-base/platform/users/web-dashboard/operation-tagging) — Apply tags to operations and filter the Operations tab by tag
* [Reporting](/knowledge-base/platform/users/web-dashboard/reporting) — View statements and download balance and transaction reports
* [Tax center](/knowledge-base/platform/users/web-dashboard/tax-center) — Supply cost basis information, manage tax documents, and certify tax information
* [Deposit attributions](/knowledge-base/platform/users/web-dashboard/deposit-attributions) — Identify pending deposit sources
* [Trusted sources](/knowledge-base/platform/users/web-dashboard/trusted-sources) — Manage automatic deposit attribution
# Reporting
Source: https://docs.anchorage.com/knowledge-base/platform/users/web-dashboard/reporting
View statements, download balances and transaction reports, and find your organization's tax documents.
The **Reporting** section of the Anchorage Digital web dashboard is where you view monthly statements, download balances and transaction reports, and manage your organization's tax documents.
**Statements**, **Reports**, and **Tax center** are available only in the web dashboard — they're not accessible from the Anchorage Digital iOS app.
## Statements
Statements are issued monthly and break down your holdings by asset. Go to **Statements** to view and download your monthly account statements.
## Reports
Balance and transaction reports can be downloaded or scheduled for automatic delivery to recipients—for example, twice daily. Go to **Reports** to download daily balances and asset address reports. Whether statements and reports send automatically is configured per organization, so check your delivery settings if you expect them and aren't receiving them.
### Current limitations
Reports break down balances per wallet, but that breakdown doesn't yet include the [available, staked, unclaimed, and total view](/knowledge-base/platform/users/web-dashboard/reading-balances) shown in the web dashboard. If you need that level of detail in a report, contact your client experience team for options in the meantime.
## Tax center
Supply cost basis information for deposits, manage tax documents such as 1099-MISC forms, and certify your organization's tax information in the [Tax center](/knowledge-base/platform/users/web-dashboard/tax-center).
## Related topics
* [Tax center](/knowledge-base/platform/users/web-dashboard/tax-center) — Supply cost basis information, manage tax documents, and certify tax information
* [View operations](/knowledge-base/platform/users/web-dashboard/operations) — Review pending and past account operations
* [Operation tagging](/knowledge-base/platform/users/web-dashboard/operation-tagging) — Create tag-filtered transaction reports
* [Configure document delivery](/knowledge-base/platform/users/web-dashboard/settings#document-delivery) — Manage distribution lists for statements and tax documents
* [Deposit attributions](/knowledge-base/platform/users/web-dashboard/deposit-attributions) — Identify pending deposit sources
# Settings
Source: https://docs.anchorage.com/knowledge-base/platform/users/web-dashboard/settings
Configure invoices and document delivery from the web dashboard.
Configure invoices and document delivery from the web dashboard, and manage your team, policies, and trusted sources and destinations.
Manage users, roles, and administrator and vault policies.
Add, manage, and remove trusted withdrawal destinations.
Manage trusted deposit sources for automatic attribution.
## Document delivery
Navigate to **Settings**, then **Document delivery** and click the edit button to set up or edit the distribution list for each document category. You can specify different recipients per legal entity onboarded with Anchorage Digital.
To configure invoice delivery specifically, navigate to **Invoices** and enter or edit email recipient details. For more on viewing, paying, and managing invoices, see [Invoices](/knowledge-base/platform/users/web-dashboard/invoices).
# Tax center
Source: https://docs.anchorage.com/knowledge-base/platform/users/web-dashboard/tax-center
Supply cost basis for deposits, manage tax documents, and certify your organization's tax information.
The Tax center is where you manage your organization's tax information — add cost basis for deposits, access tax documents, and manage tax certifications, all in one place.
Manage cost basis information for assets you deposited into Anchorage Digital.
View, download, and share tax documents.
Manage tax certifications for your accounts.
Anchorage Digital does not provide financial, tax, or legal advice. Consult a qualified professional for guidance specific to your situation.
## Cost basis
When you deposit assets into Anchorage Digital that you acquired elsewhere, we know the date they arrived but not what you originally paid for them or when you first acquired them. That original price and date — the **cost basis** — is what determines your gain or loss when you later sell or move the asset, and it's required for accurate tax reporting.
Provide cost basis and acquisition dates for deposits by downloading, editing, and uploading a CSV through the **Cost basis** tab. If you need to submit a large number of tax lots across many deposits, [providing cost basis via API](/knowledge-base/platform/developers/tax/cost-basis) may be more efficient. Contact your client experience team to learn more.
For general questions about cost basis and tax reporting, see the [cost basis FAQ](/knowledge-base/platform/users/web-dashboard/cost-basis-faq).
### Completing the report
Download the report from the **Cost basis** tab, edit it locally, then upload the updated version.
### CSV columns
The deposits report CSV contains two types of columns:
**Pre-populated columns (do not modify):**
* **Account ID** — Account name associated with the deposit.
* **Deposit ID** — Unique identifier for the deposit transaction. This is the only pre-populated column used to match your updates to the correct deposit — the rest are for your reference and aren't validated during upload.
* **Deposit date & time** — Date and time in `YYYY-MM-DDThh:mm:ssZ` format.
* **Asset type** — Asset type on the deposit (e.g., BTC, ETH).
* **Deposit quantity** — Total quantity deposited.
**Columns you must fill in:**
* **Lot quantity** — The amount of the asset in the specific tax lot.
* **Lot cost basis** — The total cost of this tax lot in US dollars.
* **Lot acquisition date & time** — The date the asset was acquired in `YYYY-MM-DDThh:mm:ssZ` format.
### Handling multiple tax lots
A single deposit can have multiple tax lots if the asset was acquired on separate occasions.
* **Single tax lot:** Fill in the required fields on the existing row. The lot quantity must equal the deposit quantity.
* **Multiple tax lots:** Duplicate the row for each additional lot, keep the pre-populated fields identical across all rows, then fill in the lot details for each. The sum of all lot quantities must equal the deposit quantity.
For example, a deposit of 5 BTC could break down into three lots: 1 BTC acquired for $100, 2.5 BTC acquired for $500, and 1.5 BTC acquired for \$400, each on a different date.
### Validation rules
| Rule | Description |
| ---------------------- | ------------------------------------------------------------------------------------------------------------------- |
| Quantity match | Total lot quantity for a deposit ID must equal the original deposit quantity. Partial allocations aren't supported. |
| Date and time accuracy | Acquisition date and time must be on or before the deposit date and time. |
| Lot limit | Maximum of 100 tax lots per deposit. [Contact support](mailto:tax@anchorage.com) if you exceed this limit. |
| File size | Maximum of 10 MB or 5,000 deposits per upload. Split larger files and upload them separately. |
### Upload and review
Save your file as a CSV and upload it through the **Cost basis** tab.
* If we find no errors, your cost basis updates immediately.
* If some rows have errors, we process the valid rows and generate a new error report with only the failed rows and details on how to fix them. Correct the file and re-upload it.
If you have questions or run into upload issues, [contact support](mailto:tax@anchorage.com).
## Documents
The **Documents** tab lets you view, filter, and manage your organization's tax documents, such as 1099-MISC forms.
* **Filter** documents by document type or account.
* **Download** documents by selecting the ones you need and selecting **Download**, or use the bulk download option to download all available forms.
* **Share** tax documents by emailing them directly to recipients.
* Select **View expected tax document issue dates** to see when we expect specific document types to be available.
If an account isn't eligible to receive tax documents, forms won't appear in the Tax center. You can still manage delivery preferences for that account.
### Managing tax document delivery
Select the **more options** menu, then select **Manage tax document delivery** to add or remove recipients. Anyone you add receives an email notification whenever a new tax document becomes available.
## Tax settings
The **Tax settings** tab shows the tax certification status for each of your accounts. Tax certifications confirm your organization's tax information and are required for accurate tax reporting.
Each account shows one of three statuses:
| Status | Meaning |
| --------------- | ----------------------------------------------------- |
| Valid | The certification is complete and current. |
| Needs attention | The certification has an error or is no longer valid. |
| Not complete | The certification is missing. |
To certify an account, select it, then select **Complete**. If the certification needs attention, select **Update** instead, then fill in and submit the form.
For questions about IRS forms, FATCA, and treaty benefits, see the [tax certification FAQ](/knowledge-base/platform/users/web-dashboard/tax-certification-faq).
## Related topics
* [Reporting](/knowledge-base/platform/users/web-dashboard/reporting) — View statements and download balance and transaction reports
* [View operations](/knowledge-base/platform/users/web-dashboard/operations) — Review pending and past account operations
* [Configure document delivery](/knowledge-base/platform/users/web-dashboard/settings#document-delivery) — Manage distribution lists for statements and tax documents
# Tax certification FAQ
Source: https://docs.anchorage.com/knowledge-base/platform/users/web-dashboard/tax-certification-faq
Answer common questions about tax certification, IRS forms, and FATCA classification.
Anchorage Digital collects and certifies your tax information using IRS Forms W-8 and W-9. Your answers determine which specific tax certification you complete (W-9, W-8BEN, W-8BEN-E, or W-8IMY). To learn more, review the [IRS instructions](https://www.irs.gov/forms-instructions).
Anchorage Digital does not provide financial, tax, or legal advice. Consult a qualified professional for guidance specific to your situation.
## Why we collect tax information
We're required by US tax law to collect certain details to verify your tax status. This helps us report payments correctly to the IRS (Internal Revenue Service) and determine whether any tax withholding applies.
Providing accurate information helps ensure your payments are processed smoothly and without unnecessary withholding.
The tax details you provide cover payments and income made to you or your organization that must be reported to the IRS. This includes:
* Trading activity, proceeds, and cost basis
* Cost basis data for deposits
* Staking rewards paid by broker
* Airdrops
* Stablecoin rewards (e.g., PYUSD, USDG, USDT)
* Fiat interest
US law requires you to confirm your taxpayer identification number and tax status. Certifying confirms that you (or your account) are the beneficial owner of the income or proceeds and establishes your tax status under US law, so Anchorage Digital can report payments correctly to the IRS and apply the correct withholding.
If your information is incomplete or incorrect, we may be required by the IRS to apply backup withholding to payments we make to you.
Incorrect or missing information can also delay your payments until the issue is resolved. Providing accurate details ensures the form is complete and can be certified properly.
## Choosing your form and account type
You don't pick the form directly. The questionnaire first asks whether you're an individual and whether you're a US person, then selects the right form:
* **US person** → **Form W-9**
* **Non-US individual** → **Form W-8BEN**
* **Non-US entity** → **Form W-8BEN-E**
* **Non-US intermediary or flow-through entity** → **Form W-8IMY**
You'll also be asked which best represents your account type — **Individual**, **Entity**, or **Intermediary** — which shapes the questions that follow.
It means the individual identified on the form isn't a US citizen, US resident alien, or domestic entity. This certification ensures that payments are treated under the rules for foreign persons, which affects withholding and reporting.
The form asks you to classify yourself under US tax rules so the correct form and certifications apply.
**If you're a US filer:**
* **Individual**
* **Sole proprietor** — Someone who owns an unincorporated business by themselves.
* **Limited liability company** — A state-registered business structure. If you select this, you'll then select the LLC's classification: **C corporation**, **S corporation**, or **partnership**.
* **Single-member limited liability company** — An SMLLC is an LLC with a single owner, and isn't treated as separate from its owner for US tax purposes unless an election has been made.
* **C corporation** — A standard, independent legal entity owned by shareholders.
* **S corporation** — A special corporation passing profits directly to owners.
* **Partnership** — An unincorporated business co-owned by two or more people.
* **Trust/estate** — A legal arrangement holding assets for named beneficiaries.
* **Disregarded entity** — An entity that isn't separate from its owner for US tax purposes, unless an election has been made.
* **Other** — Any other type of US entity not listed above. If you select this, describe your entity.
**If you're a non-US entity or intermediary:**
As an entity:
* **Corporation** — A company organized as a corporation under local law.
* **Complex trust** — A trust that may accumulate income, distribute to beneficiaries, or make charitable contributions.
* **Tax exempt organization** — An organization exempt from tax under local law.
* **Private foundation** — A non-governmental, non-profit organization funded and controlled privately.
* **International organization** — A recognized multinational organization (e.g., United Nations, World Bank).
* **Central bank of issue** — A foreign central bank that issues currency.
* **Foreign government controlled entity** — A company owned or controlled by a foreign government.
* **Foreign government integral part** — A department or agency that's an integral part of a foreign government.
* **Estate** — An arrangement managing assets of a deceased person.
* **Disregarded entity** — An entity treated as part of its owner for tax purposes. If you select this, provide its name.
As an intermediary:
* **Qualified intermediary** — A non-US financial institution or foreign branch with a formal withholding agreement with the IRS.
* **Nonqualified intermediary** — A foreign financial institution or person acting as an intermediary without a QI agreement with the IRS.
* **Territory financial institution** — A financial institution incorporated or organized under the laws of a US territory (e.g., Puerto Rico, Guam, US Virgin Islands).
* **US branch** — A domestic office or branch operated within the United States by a foreign bank or foreign insurance company.
* **Withholding foreign partnership** — A foreign partnership with a direct withholding agreement with the IRS.
* **Withholding foreign trust** — A foreign trust with a direct withholding agreement with the IRS.
* **Nonwithholding foreign partnership** — A foreign partnership without a withholding agreement with the IRS.
* **Nonwithholding foreign simple trust** — A foreign trust required by its terms to distribute all of its annual income currently, and that lacks an IRS withholding agreement.
* **Nonwithholding foreign grantor trust** — A foreign trust where the grantor retains control over the assets, and that lacks an IRS withholding agreement.
If you're not sure whether your account qualifies, confirm this detail with your Legal or Finance team.
## Backup withholding and exemptions for US filers
Backup withholding is a 24% withholding on certain payments that the IRS may require if a taxpayer fails to provide a correct taxpayer identification number (TIN) or has otherwise underreported. By certifying that you're not subject to backup withholding, you confirm that the IRS hasn't notified you that withholding should apply.
The exempt payee code applies if you're a US payee exempt from backup withholding. Exempt payees include:
1. An organization exempt from tax under section 501(a), any IRA, or a custodial account under section 403(b)(7) if the account satisfies the requirements of section 401(f)(2).
2. The United States or any of its agencies or instrumentalities.
3. A state, the District of Columbia, a US commonwealth or territory, or any of their political subdivisions or instrumentalities.
4. A foreign government or any of its political subdivisions, agencies, or instrumentalities.
5. A corporation.
6. A dealer in securities or commodities required to register in the United States, the District of Columbia, or a US commonwealth or territory.
7. A futures commission merchant registered with the Commodity Futures Trading Commission.
8. A real estate investment trust.
9. An entity registered at all times during the tax year under the Investment Company Act of 1940.
10. A common trust fund operated by a bank under section 584(a).
11. A financial institution as defined under section 581.
12. A middleman known in the investment community as a nominee or custodian.
13. A trust exempt from tax under section 664, or described in section 4947.
If you're not sure whether your account qualifies, confirm this detail with your Legal or Finance team.
This field applies if you're claiming exemption from FATCA (Foreign Account Tax Compliance Act) reporting. FATCA exemption codes include:
* **A** — An organization exempt from tax under section 501(a), or any individual retirement plan as defined in section 7701(a)(37).
* **B** — The United States or any of its agencies or instrumentalities.
* **C** — A state, the District of Columbia, a US commonwealth or territory, or any of their political subdivisions or instrumentalities.
* **D** — A corporation whose stock is regularly traded on one or more established securities markets, as described in Regulations section 1.1472-1(c)(1)(i).
* **E** — A corporation that's a member of the same expanded affiliated group as a corporation described in Regulations section 1.1472-1(c)(1)(i).
* **F** — A dealer in securities, commodities, or derivative financial instruments (including notional principal contracts, futures, forwards, and options) registered as such under the laws of the United States or any state.
* **G** — A real estate investment trust.
* **H** — A regulated investment company as defined in section 851, or an entity registered at all times during the tax year under the Investment Company Act of 1940.
* **I** — A common trust fund as defined in section 584(a).
* **J** — A bank as defined in section 581.
* **K** — A broker.
* **L** — A trust exempt from tax under section 664, or described in section 4947(a)(1).
* **M** — A tax-exempt trust under a section 403(b) plan or section 457(g) plan.
## FATCA classification for non-US filers
Your FATCA entity type identifies your organization under the FATCA (Foreign Account Tax Compliance Act) rules. It helps determine whether and how we report payments to the IRS. FATCA entity types include:
* **Exempt beneficial owners** — Entities generally exempt from FATCA, including foreign governments, central banks, and certain retirement funds or international organizations.
* **Foreign financial institutions (FFIs)** — Non-US entities that hold financial accounts or act as financial intermediaries, such as banks, investment funds, or custodians.
* **Non-financial foreign entities (NFFEs)** — Non-US entities that aren't financial institutions, typically operating businesses engaged in trade, manufacturing, or services.
* **Other statuses** — Accounts that aren't considered financial accounts for FATCA purposes, and don't fall into the FFI, NFFE, or exempt categories.
If you're unsure how your organization is classified, confirm this detail with your Legal or Finance team.
FATCA status describes your account's reporting obligations under FATCA. The options available depend on the FATCA entity type you selected.
**If your account is an exempt beneficial owner:**
* **Entity wholly owned by exempt beneficial owners** — Owned entirely by governments, international organizations, or exempt retirement funds.
* **Exempt retirement plan** — A pension or retirement plan exempt from FATCA reporting.
* **Foreign government / US possession / central bank of issue** — Accounts owned by governments, central banks, or US territories.
* **International organization** — A recognized multinational organization (e.g., United Nations, World Bank).
**If your account is a foreign financial institution (FFI):**
* **Certified deemed-compliant investment advisers/managers** — Investment managers that meet specific FATCA compliance criteria.
* **Certified deemed-compliant limited-life debt investment entity** — Investment entities with limited-life debt structures that qualify for special FATCA status.
* **Certified deemed-compliant local bank** — Local banks that meet FATCA compliance requirements.
* **Certified deemed-compliant low-value accounts** — Financial institutions managing only small accounts that qualify for simplified FATCA treatment.
* **Certified deemed-compliant sponsored, closely held investment vehicle** — Investment vehicles sponsored by another entity that qualifies as deemed-compliant.
* **Excepted inter-affiliate** — FFI accounts among related entities that meet FATCA exceptions.
* **Non-participating** — FFIs that don't comply with FATCA.
* **Non-reporting IGA** — FFIs that don't report under an Intergovernmental Agreement (IGA).
* **Owner-documented** — FFIs that rely on documentation of account holders for FATCA compliance.
* **Participating** — FFIs actively complying with FATCA reporting requirements.
* **Registered deemed-compliant (other than model 1)** — Other FFIs meeting deemed-compliant criteria and registered with the IRS.
* **Reporting model 1** — FFIs reporting under FATCA Model 1 IGA agreements.
* **Reporting model 2** — FFIs reporting under FATCA Model 2 IGA agreements.
* **Restricted distributor** — FFIs distributing financial products under certain FATCA restrictions.
* **Sponsored (without GIIN)** — FFIs sponsored by another entity but without a Global Intermediary Identification Number (GIIN).
* **Territory financial institution** — FFIs based in US territories.
**If your account is a non-financial foreign entity (NFFE):**
* **501(c) organization** — Non-US equivalent of a US tax-exempt nonprofit.
* **Active** — An NFFE actively conducting business (not primarily earning passive income).
* **Direct reporting** — An NFFE reporting directly to the IRS for FATCA purposes.
* **Excepted nonfinancial entity in liquidation or bankruptcy** — NFFEs in liquidation or bankruptcy that qualify for FATCA exceptions.
* **Excepted nonfinancial group entity** — Part of a nonfinancial group meeting FATCA exceptions.
* **Excepted nonfinancial start-up company** — Newly formed NFFEs qualifying for FATCA exceptions.
* **Excepted territory** — NFFEs in US territories qualifying for FATCA exceptions.
* **Nonprofit organization** — NFFEs that operate as nonprofits under local law.
* **Passive** — NFFEs earning primarily passive income (e.g., dividends, interest).
* **Publicly traded or affiliate of a publicly traded corporation** — NFFEs traded on public markets or controlled by a publicly traded company.
* **Sponsored direct reporting** — NFFEs reporting through a sponsoring entity.
If you're unsure how your account is classified, confirm this detail with your Legal or Finance team.
A GIIN (Global Intermediary Identification Number) is a unique number the IRS assigns to financial institutions that register under FATCA. You'll need it if your organization is a foreign financial institution (FFI) required to report under FATCA.
A GIIN is only valid for:
* Participating FFIs
* Reporting Model 1 FFIs
* Reporting Model 2 FFIs
* Registered deemed-compliant FFIs (other than Model 1)
You can find your GIIN on the IRS FATCA FFI list, in your organization's FATCA registration documents, or by contacting your Legal or Finance team. If your account isn't one of these FFIs, you won't have a GIIN.
## Treaty benefits and keeping your form current
If your country has an income tax treaty with the US, you may be able to claim a reduced withholding rate. The form asks whether you're eligible, then collects:
* **Treaty country**
* **Type of income** — Business profits, royalties (other copyright), or independent personal services
* **Withholding rate and treaty article/paragraph**
* **Limitation on benefits (LOB) provision** — e.g., government; tax-exempt pension trust or fund; publicly traded corporation; company meeting the ownership and base-erosion test; and others
If you're not claiming a treaty benefit, you can proceed without making a claim.
By submitting, you agree to submit a new form within 30 days if any certification becomes incorrect, and, where applicable, to notify us of a change in circumstances affecting your tax residency.
A submitted form can also stop being reliable and require resubmission. Common reasons include US indicia on a W-8 (a US address, US place of birth, or US phone number), a US permanent address on a W-8, a PO box or care-of address used as a permanent address, an expired W-8 (its reliability lapses at the end of the third calendar year after signing), or a change in circumstances.
## Related topics
* [Tax center](/knowledge-base/platform/users/web-dashboard/tax-center#tax-settings) — Supply cost basis information, manage tax documents, and certify tax information
* [Reporting](/knowledge-base/platform/users/web-dashboard/reporting) — View statements and download balance and transaction reports
# Team & policies
Source: https://docs.anchorage.com/knowledge-base/platform/users/web-dashboard/team-policies
Manage users, roles, and administrator and vault policies from the web dashboard.
## Team management
In **Settings**, under **Access control**, select **Team** to manage users in your organization.
### Adding a user
Click **Add user**.
Choose the role this user will have in your organization, then click **Next**.
For users with the Administrator or Operator role, select the vault policies to assign them to. The user will be added to every vault those policies apply to. Click **Next**.
Review the user's roles and privileges. For each selected vault policy, set whether the user can **Initiate and approve operations** or **Initiate only**. Click **Next**.
Enter the user's email address and press **Submit**. The user will be added to your organization once they complete enrollment on their phone and the operation is approved.
Users with Initiate and approve permissions still need to be added to a policy's approval rules to approve specific operation types.
### Removing a user
Select the options menu for a user and click **Remove** to remove them from the organization.
### Viewing user details
Click on a user on the Team page to view their email address, date added, roles, and assigned policies.
## Roles
In **Settings**, under **Access control**, select **Roles** to review the roles and permissions across your organization. Click **Download structure** to export a report of each user's roles and permissions. Select any system role to see its details and the list of users assigned to it.
## Administrator policy
In **Settings**, under **Access control**, select **Policies**, then select **Admin policy** to view its details. To make changes, click **Edit policy** or use the iOS app.
The **Rules** and **Users** tabs behave the same here as on iOS. See [Administrator policy](/knowledge-base/platform/users/administrator-policy) for base quorums and sub-quorums, and [Rules](/knowledge-base/platform/users/rules) for adding, editing, and deleting rules.
Any changes are subject to quorum approval according to the policy in place. You will be prompted to submit biometric approval on your iOS device.
## Vault policies
In **Settings**, under **Access control**, select **Policies**, then select a vault policy to view its details. To make changes, click **Edit policy** or use the iOS app.
See [Vault policies](/knowledge-base/platform/users/vault-policies) for quorums, sub-quorums, and assigned vaults, and [Rules](/knowledge-base/platform/users/rules) for rule outcomes and conditional rules.
### Managing policy users
On the **Users** tab of either policy, click **Edit users** to add users, edit permission levels, or remove users.
* Adding a user with **Initiate and approve** permissions adds them as an approver of the policy's default rule.
* Demoting a user to **Initiate only** removes them from all rules.
### Assigning vaults to a policy
Select the **Assigned vaults** tab and click **Assign vaults** to assign a vault policy to additional vaults.
### Changing the policy assigned to a vault
You can change the policy assigned to a vault in two ways:
1. Go to **Settings**, edit a policy, and assign it to the vault.
2. Go to **Dashboard**, enter a vault, go to **Settings**, scroll down, and select **Change policy**. Then select an existing policy or create a new one specifically for that vault.
# Web3 access
Source: https://docs.anchorage.com/knowledge-base/platform/users/web3-access
Connect to Web3 apps via Chrome extension and WalletConnect, and initiate BUIDL redemptions.
Anchorage Digital supports interactions with a growing list of decentralized apps (dApps) through the Anchorage Browser Extension and WalletConnect. Administrators control which vaults are enabled to interact with each app and can monitor all connection activity within their account.
Anchorage Digital iOS app version 2.41.0 or later is required to use approved apps in the Web3 portal.
## Why Web3 access matters
A **smart contract** is a program that runs on a blockchain — it holds funds and executes rules automatically, with no intermediary. A **decentralized app (dApp)** is the interface to one or more of those contracts. Together they're how a growing share of institutional activity now happens on-chain.
For an institution, that's where real use cases live:
* **Tokenized assets and redemptions** — for example, redeeming BlackRock's BUIDL fund for USDC through Securitize (walked through below).
* **DeFi** — lending, borrowing, providing liquidity, and swapping assets directly with on-chain protocols.
* **On-chain governance** — voting on protocol proposals for assets you hold.
* **Restaking and staking protocols** — interacting with contracts like EigenLayer.
Connecting a wallet to a smart contract carries risk: an approval granted to a malicious contract can move funds. Anchorage Digital applies custody controls to these interactions: administrators approve which dApps each vault can connect to, connections run through the Anchorage Browser Extension or WalletConnect, and **every on-chain action requires quorum approval and Anchorage Digital review** before it executes.
## Getting started
Download the [Anchorage Digital Browser Extension](https://chromewebstore.google.com/detail/anchorage-digital/fadcgekaahkbmhjnpdhldednpbfpmkfl) from the Chrome Web Store to connect your Anchorage wallets directly to approved dApps.
WalletConnect is an open-source protocol that enables communication between blockchain applications and mobile crypto wallets, allowing users to review and approve signature requests directly in the iOS app.
## Adding apps to your approved list
Account administrators control which third-party apps can be added to their organization's approved list. Only apps on the approved list can be used by vault members.
In the web dashboard, select **Settings**, then **Web3 access**.
From the list of Anchorage Digital trusted apps, click the **plus icon** next to the app you want to add.
Choose which vaults will be able to make connections to this app. Click **Approve** to confirm your selection. Upon accepting the app terms, your account's approved list will be updated.
Click on any app in the **Approved apps** list to edit vault access or remove the app from your organization's approved list.
## Chrome browser extension
The Anchorage Digital browser extension connects your Anchorage wallets directly to decentralized apps (dApps). It serves as the institutional bridge between your Anchorage wallets and Anchorage-approved dApps.
### Downloading and logging in
Download the [Anchorage Digital browser extension](https://chromewebstore.google.com/detail/anchorage-digital/fadcgekaahkbmhjnpdhldednpbfpmkfl) from the Chrome Web Store.
Open the browser extension in Chrome.
Open the Anchorage Digital iOS app and tap the **QR Code** icon. Scan the QR code displayed in the browser extension.
Review the location of the device requesting access and allow access from the iOS app.
### Finding approved apps
In the **Explore** tab, the first section shows all apps your organization administrator has approved. Click on any app icon to open it in a new tab.
If an app has not been approved by your administrator, you cannot use it until they configure the allowed vaults and accept the Terms and Conditions on the web dashboard. Contact your administrator or reach out to your client experience manager to request certification of additional apps.
### Connecting a wallet to an external app
Open the external decentralized app in your browser.
Select **Connect** in the top right corner of the app.
Choose **Anchorage Digital** from the list of wallet options. If you do not see Anchorage Digital listed, contact your client experience manager.
Filter by vault or select a recently used wallet. Select the wallet to view its details and balance information.
Click **Connect** to complete the connection.
You can only connect to wallets that are part of vaults allowed by your organization administrator. Open the **Vaults** dropdown to see the "Allowed vault" badge on permitted vaults.
### Switching wallets
Open the browser extension and navigate to the **Wallets** tab to see your currently connected wallet.
Search by vault, network, or name.
Select **Connect** on the desired wallet card to switch the connection.
Alternatively, switch wallets from the **Wallet details** page by selecting **Connect to external app**.
### Disconnecting a wallet
You can disconnect your wallet in three ways:
* **From the dApp icon:** Open the browser extension, select the dApp icon in the top right, and select **Disconnect wallet**.
* **From Wallet details:** Select the connected wallet, tap **More** (three dots) in the top right, and select **Disconnect wallet**.
* **From the external app:** Select the connected wallet in the external app interface and select **Disconnect wallet**.
### Initiating operations from an external app
With an established connection, follow the instructions on the dApp webpage to submit your selection. Once submitted, an operation will appear for review and approval in the Anchorage Digital iOS app.
Follow the instructions on the dApp webpage and confirm or submit your selection.
Open the iOS app and navigate to **Pending activity** by tapping the bell icon at the bottom of the screen. Tap the **External operation needs approval** notification.
Review all operation details. If satisfied, endorse the operation — quorum approval is required to complete it.
### Enabled networks
New chains are added to the browser extension regularly. You can view all enabled chains in the **Networks** filter within the **Wallets** tab.
### Disconnecting active sessions (administrators)
Account administrators can view all active wallet connections and disconnect any member's session from the web dashboard.
Each active wallet connection appears as an individual card with details. Click **Disconnect** to terminate any vault member's active connection with an app.
## WalletConnect
WalletConnect allows vault members to connect their Anchorage Digital iOS wallet to approved apps using a QR code scan.
### Connecting the iOS app to an external app
Once an app has been added to your account's approved list, vault members can connect their Anchorage Digital iOS wallet to initiate supported actions.
On your desktop browser, open the approved app's webpage (e.g., [https://snapshot.org](https://snapshot.org)). In the upper-right corner, click **Connect wallet** and choose **WalletConnect** to generate a QR code.
Open the Anchorage Digital iOS app and tap the **QR code icon** in the upper-right corner of the screen. Point the iOS camera at the QR code to initiate the connection.
Select which wallet to connect from the wallet selection screen in the iOS app, then tap **Continue**. This completes the connection.
If successful, you will see confirmation on both the iOS app and the external app webpage.
### Initiating operations via WalletConnect
With an established connection, follow the app's instructions and submit your selection. An operation will appear for review and approval in the Anchorage Digital iOS app.
Tap the bell icon to navigate to **Pending activity**, then tap **External operation needs approval** to review the details. Endorse the operation to proceed — quorum approval is required.
For further questions related to Connected Apps and WalletConnect, contact your client experience manager.
## BUIDL redemptions via Securitize
Securitize manages digital securities and serves as the transfer agent for BUIDL, a money market fund managed by BlackRock. Anchorage Digital users can interact with the Securitize dApp via WalletConnect to redeem BUIDL for USDC.
### Overview
A completed BUIDL redemption triggers:
* A withdrawal of BUIDL from your Anchorage Digital wallet
* A deposit of USDC into your Anchorage Digital wallet
* The counterparty is always Circle
* The source is always the same smart contract
### Who can use the Securitize dApp
Users who hold BUIDL on Anchorage Digital and are onboarded with Securitize can use the dApp. Only an authorized user with Securitize credentials can initiate a redemption.
### Step 1: Connect Securitize to your account
Log in to your Anchorage Digital account that holds BUIDL in custody.
Go to **Web3**, then **Add an App**.
Select **Securitize** from the app dropdown.
Choose the vaults holding BUIDL that you want to connect.
Add Securitize to the allowlist and accept the app terms.
### Step 2: Select and prepare your wallet
Open the wallet holding your BUIDL.
Verify the wallet has enough ETH for gas fees. Approximately 0.1 ETH is recommended.
If the balance is insufficient, fund your wallet with ETH before proceeding.
### Step 3: Approve a redemption amount
New users must approve a redemption amount before proceeding. Returning users can skip this step if an approval is already in place.
Navigate to the Securitize app in your browser.
Go to **Wallets**, then **Connect Anchorage Digital wallet**. Scan the QR code using the scanner in the top-right corner of the iOS app.
Select **Sell for USDC**, specify the amount, and select **Sell**.
* **Quorum approval:** Users with the correct permissions must endorse the approval in the iOS app.
* **Ops review:** Anchorage Digital performs a risk review of the transaction.
### Step 4: Redeem approved amounts
Once an amount is approved, you can proceed with the redemption.
Select **Sell for USDC**, specify the amount, and click **Sell**.
Review and confirm the redemption in the Securitize app.
* **Quorum approval:** Users must endorse the redemption in Anchorage Digital.
* **Ops review:** Anchorage Digital completes a back-office approval.
### Step 5: View updated balance
Once completed, the redeemed USDC will appear in your Anchorage Digital wallet within 5–10 minutes.
# Interacting with smart contracts
Source: https://docs.anchorage.com/knowledge-base/porto/advanced/smart-contracts
Advanced guide to using smart contracts and custom contract interactions from Porto.
You're viewing **Porto** documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/users/overview)
Smart contracts are self-executing programs on the blockchain. Porto allows advanced users to interact with any smart contract, from common DeFi protocols to custom enterprise contracts. This guide covers contract interactions, approval management, and best practices.
This page is for advanced users. If you're new to smart contracts, see [Using DApps and smart contracts](/knowledge-base/porto/assets/using-dapps) first.
## What is a smart contract interaction
A smart contract interaction is a transaction that:
* Calls a function on a smart contract (not just sending assets)
* May execute complex logic (trading, lending, voting, etc.)
* Can be reverted if something goes wrong (but you still pay gas)
* Requires the contract address and function details to execute
Smart contracts include:
* **DeFi protocols** — Uniswap, Aave, Curve, etc.
* **Governance contracts** — Voting and proposal contracts
* **Bridge contracts** — Cross-chain asset transfers
* **Custom enterprise contracts** — Organizations' internal smart contracts
* **NFT contracts** — Minting, trading, staking contracts
## Connect to a smart contract
There are several ways to interact with smart contracts from Porto:
### Via a DApp interface
Most smart contracts have a user interface (DApp). See [Using DApps](/knowledge-base/porto/assets/using-dapps) for the standard flow.
### Direct contract interaction
For contracts without a user interface:
You'll need:
* **Contract address** — The blockchain address of the contract (e.g., 0x...)
* **Function signature** — The name and parameters of the function you're calling
* **Contract ABI** — Application Binary Interface (tells Porto how to call the contract)
* **Parameters** — Values to pass to the function
Look for **Contract interaction**, **Direct contract call**, or **Custom contract** in Porto's settings or advanced menu. This feature may require admin permissions.
Paste the contract address carefully. Verify it matches the official contract (check multiple sources).
If you have the contract ABI, Porto can show you available functions. Otherwise, you'll need to enter the function signature manually.
Fill in the parameters the function requires. Be precise — wrong values will cause the transaction to fail.
Porto will show you the transaction details before execution. Review carefully.
Complete biometric authentication to execute the contract call.
## Approvals and token permissions
Many DeFi operations require granting a contract permission to spend your tokens. This happens in two steps:
1. **Approve** — You approve a contract to spend up to a certain amount of a token
2. **Execute** — The contract then uses that allowance to execute the operation
### Approving a token spend
Determine which contract needs approval (usually the DEX or protocol you're using).
Decide how much of your token to approve:
* **Exact amount** — Approve only what you need for one transaction
* **High amount** — Approve a large amount for multiple transactions (more convenient, slightly riskier)
* **Unlimited** — Some users approve unlimited amounts (highest convenience, highest risk)
Create an approval transaction. This transaction has no direct effect but grants permission.
The approval must confirm on-chain before the next transaction can use it.
Once approved, the contract can execute your transaction (swap, stake, lend, etc.).
## Common smart contract interactions
| Interaction | Typical function | Risk | Gas cost |
| :-------------------- | :----------------------------- | :----- | :--------- |
| **Swap (DEX)** | `swap()`, `exactInputSingle()` | Medium | Low-Medium |
| **Stake tokens** | `stake()`, `deposit()` | Medium | Low |
| **Provide liquidity** | `addLiquidity()`, `mint()` | High | High |
| **Borrow** | `borrow()`, `deposit()` | High | Medium |
| **Vote (governance)** | `vote()`, `castVote()` | Low | Low |
| **Harvest rewards** | `harvest()`, `claim()` | Low | Low |
| **Bridge transfer** | `bridge()`, `lock()` | High | High |
## Understanding gas and transaction costs
Every smart contract call costs gas (network fees):
* **Gas price** — Set by the blockchain network (you cannot control this)
* **Gas limit** — Maximum gas this transaction can use (set by the contract or estimated)
* **Total cost** — Gas price × Gas used = Transaction cost
Porto will show you estimated gas costs before execution. Actual costs may vary based on network congestion.
## Recognizing risky contracts
Be cautious of smart contracts that:
* **Lack code verification** — Check if the contract has been audited and code verified on a block explorer
* **Require your private key** — Never share your private key with any contract or off-chain tool
* **Request unusual permissions** — Be suspicious of contracts asking for unlimited approvals
* **Are newly deployed** — New contracts have higher risk of bugs or scams
* **Have no documentation** — Avoid contracts with no clear description of what they do
* **Demand urgent action** — Scams often create artificial time pressure
Always research a contract on community forums and block explorers before using it.
## Reverting failed transactions
If a smart contract transaction fails (reverts):
1. **Check the reason** — Your transaction receipt will show why it failed (insufficient balance, wrong parameters, etc.)
2. **Fix and retry** — Correct the issue and resubmit the transaction
3. **You still pay gas** — Even if the transaction fails, you pay gas fees
4. **Check for slippage** — If swapping, slippage or price impact may have caused failure
## Gas estimation and optimization
Porto estimates gas before you execute a transaction. Tips to reduce gas costs:
* **Lower gas price** — During quiet times, gas is cheaper; use lower gas if you're not in a hurry
* **Batch operations** — Combine multiple interactions into one transaction if possible
* **Use efficient chains** — Layer 2 networks (Arbitrum, Optimism) have much lower gas costs
* **Avoid peak times** — Avoid network peaks when everyone is transacting
## Security best practices
* **Never share your seed phrase** — Even with trusted contracts or platforms
* **Verify contract addresses** — Always check contract addresses from official sources, not user recommendations
* **Use [trusted destinations](/knowledge-base/porto/assets/trusted-destinations)** — For known contracts you use frequently
* **Start small** — Test new contracts with small amounts first
* **Understand the contract** — Read documentation or code before using
* **Keep backups** — Store recovery materials securely in case you need to recover wallets
* **Monitor approvals** — Periodically review contracts you've approved for token spend
* **Revoke unused approvals** — If you no longer use a contract, you can revoke its token approval
## Revoking token approvals
If you've approved a contract but no longer want it to have access:
Go to a block explorer and find the token contract's approval history, or use a tool like etherscan.io to see all your approvals.
Call the token contract's `approve()` function with amount 0 to revoke the approval.
Execute the revoke transaction through Porto or a transaction builder.
Check the block explorer to confirm the approval amount is now 0.
## For organization administrators
If you're managing smart contract interactions for your organization, see your admin settings for:
* Whitelisting specific contracts users can interact with
* Setting approval limits on contract interactions
* Monitoring contract usage across your vaults
* Requiring additional approvals for high-risk contracts
# Stablecoin rewards and yield
Source: https://docs.anchorage.com/knowledge-base/porto/advanced/stablecoin-rewards
Earn yield on stablecoin holdings within your Porto vaults.
You're viewing **Porto** documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/users/overview)
Porto offers yield opportunities on stablecoin holdings. You can earn rewards by holding certain stablecoins in your vaults, with minimal additional steps beyond standard deposits and management.
## How stablecoin yield works
**Simple mechanics:**
* You hold stablecoins (USD, USDC, USDT) in your Porto vault
* Porto automatically enrolls eligible balances in yield-generating programs
* You earn rewards at scheduled intervals (daily, weekly, or monthly)
* Rewards are credited directly to your wallet
**No extra steps required:**
* You don't need to "stake" your coins — they're already in your vault
* You don't need to move assets to other contracts
* You can withdraw at any time (subject to your vault's policies)
## Eligible stablecoins
Not all stablecoins earn yield. Check which are eligible for your organization:
| Stablecoin | Common use | Yield availability | Notes |
| :--------- | :----------------- | :----------------- | :-------------------------------------- |
| **USDC** | General purpose | ✔ | Often highest yield rates |
| **USDT** | Exchanges, trading | ✔ | Varies by program |
| **USD** | Anchorage-issued | ✔ | Highest security, integrated with Porto |
| **DAI** | DeFi protocols | ✔ | May vary by vault |
| **FDUSD** | Regional | Varies | Check with your administrator |
Check your vault settings to see which stablecoins have yield enabled.
## Stablecoin yield programs
Porto offers access to different yield programs:
### Direct yield (Porto-integrated)
* **How it works** — Your stablecoins earn yield through Porto's integrated programs
* **Safety** — Assets remain in Porto vaults under your custody and policies
* **Withdrawals** — You can withdraw anytime (subject to vault policies)
* **Tax implications** — Rewards are taxable income when received
### Partner protocols
* **How it works** — Your stablecoins are deployed to trusted third-party protocols (Aave, Lido, etc.)
* **Withdrawal timeline** — Some protocols have withdrawal delays or lock periods
* **Higher yields** — Often higher than direct yield programs
* **Increased risk** — Partner protocol smart contract risk applies
Check your vault settings to see which programs are available.
## Viewing your stablecoin yield
From your vault, select a stablecoin (USDC, USD, USDT, etc.).
The wallet display will show:
* Your current stablecoin balance
* Accumulated rewards
* Annual percentage rate (APR) or yield rate
* Last reward payment date
Tap **Yield details**, **Rewards**, or **APR** to see:
* Total rewards earned (lifetime and current period)
* When rewards are paid out
* Yield program details
* Historical reward payments
## Enabling yield on stablecoins
Yield may be enabled automatically, or you may need to opt in:
From your vault, open a stablecoin wallet and look for **Settings** or **Yield options**.
You'll see whether yield is:
* **Enabled** — You're already earning rewards
* **Disabled** — Yield is available but you've opted out
* **Unavailable** — This stablecoin doesn't offer yield
If disabled, tap **Enable yield** or **Opt in**.
You'll see:
* The yield program details
* The APR or yield rate
* Any lock periods or withdrawal restrictions
* Tax and compliance information
Tap **Enable** or **Accept terms**. You may need biometric authentication.
Enabling stablecoin yield is optional. You can earn yield on part of your holdings and keep the rest in non-yielding accounts if you prefer.
## Reward payout schedule
Rewards are distributed on a schedule depending on the program:
| Schedule | Frequency | Example |
| :---------- | :-------------------- | :-------------------------- |
| **Daily** | Every 24 hours | USDC yield, most programs |
| **Weekly** | Every 7 days | Some partner protocols |
| **Monthly** | End of calendar month | Certain enterprise programs |
Rewards are credited directly to your stablecoin wallet. You'll see them in your [Activity log](/knowledge-base/porto/assets/activity-history) as reward deposits.
## Tax implications
Stablecoin rewards are taxable income. You're responsible for:
* **Reporting yield income** — Treat rewards as ordinary income on your tax return
* **Tracking reward dates** — Rewards are taxable when received, not when earned
* **Cost basis** — Rewards affect your cost basis if you later sell stablecoins
* **Jurisdiction-specific rules** — Tax treatment varies by country and region
Porto provides transaction records showing reward payments, which you can use for tax reporting. See [Cost basis tracking](/knowledge-base/platform/developers/tax/cost-basis) for details on tax reporting tools.
## Withdrawing stablecoins with active yield
If you withdraw stablecoins that are earning yield:
1. **Withdraw as normal** — Follow the standard [withdrawal](/knowledge-base/porto/assets/withdrawals) process
2. **Yield continues until withdrawal** — You earn rewards until the transaction confirms
3. **Withdrawal succeeds** — Your stablecoins leave the vault
4. **Yield stops** — Once withdrawn, the coins no longer earn rewards in Porto
If you plan to withdraw, consider the timing to maximize rewards.
## Risks and considerations
* **Market risk** — Stablecoin value can fluctuate (though minimal for USD-pegged coins)
* **Counterparty risk** — If using partner protocols, those protocols carry smart contract and operational risk
* **Regulatory risk** — Stablecoin regulation is evolving; yields may change based on new rules
* **Operational risk** — If a yield program discontinues, rewards will stop
* **Smart contract risk** — Partner protocols have audit and code risk
Porto manages these risks through:
* Vetting yield programs before offering them
* Monitoring program performance
* Limiting exposure to single programs
* Maintaining insurance where available
## Comparing stablecoin yields
Not all programs offer the same rates. To compare:
1. **Check current rates** — Rates change frequently; always check current APR
2. **Understand what's included** — Some rates are gross; others are net of fees
3. **Consider withdrawal terms** — Higher yield might come with longer lock-ups
4. **Evaluate risk tolerance** — Higher yield usually means higher risk
5. **Look at stability** — Consistent, moderate yield is often better than variable high yield
For current rates on available programs, see [Stablecoin rewards rates](/knowledge-base/porto/advanced/stablecoin-rewards-rates).
## Disabling yield
If you want to stop earning yield on a stablecoin:
Go to a stablecoin wallet and tap **Settings** or **Yield options**.
Tap **Disable yield**, **Opt out**, or **Stop earning rewards**.
You may be asked to confirm that you want to stop earning rewards.
Tap **Confirm** and complete Face ID or Touch ID.
Your stablecoin balance remains in the vault — yield simply stops accruing. You can re-enable yield at any time.
# Stablecoin rewards rates
Source: https://docs.anchorage.com/knowledge-base/porto/advanced/stablecoin-rewards-rates
Current yield rates for stablecoins in Porto vaults.
You're viewing **Porto** documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/users/overview)
This page shows current annual percentage rates (APRs) for stablecoin yield programs available in Porto. Rates are updated regularly and may vary by program, region, and market conditions.
APRs shown here are current as of this documentation update. Rates change frequently. Always check your Porto app settings for the most current rates before making decisions.
## Current stablecoin APRs
Rates are subject to change. Check Porto settings for real-time rates.
| Stablecoin | Program | APR | Lock period | Risk level | Notes |
| :--------- | :----------------- | :---------- | :---------- | :--------- | :--------------------------------------------- |
| **USD** | Porto Direct Yield | 4.5% - 5.5% | None | Low | Integrated program, no withdrawal restrictions |
| **USDC** | Circle Rewards | 3.5% - 4.5% | None | Low | Custodian-integrated, highly liquid |
| **USDC** | Aave Lending | 4.0% - 5.0% | 1-7 days | Medium | DeFi protocol, smart contract risk |
| **USDT** | Tether Rewards | 3.0% - 4.0% | None | Low | Direct from stablecoin issuer |
| **USDT** | Compound Lending | 3.5% - 4.5% | 1-7 days | Medium | DeFi protocol, smart contract risk |
| **DAI** | Aave Lending | 3.0% - 4.0% | 1-7 days | Medium | DeFi decentralized stablecoin |
| **FDUSD** | Regional Program | Varies | Varies | Varies | Regional availability, check with admin |
## Understanding the rates
**APR (Annual Percentage Rate):**
* Shows what you'd earn in one year if rates stay constant
* Actual rates may change daily or weekly
* Reward payments are made at scheduled intervals (daily, weekly, or monthly)
**Lock periods:**
* Time you must wait before withdrawing if you want to preserve rewards
* "None" means you can withdraw anytime
* Longer lock periods sometimes have higher yields
**Risk levels:**
* **Low** — Porto-integrated or major custodian programs, minimal smart contract risk
* **Medium** — DeFi protocols, smart contract risk exists but protocols are audited and established
* **High** — Newer protocols, emerging yield sources, higher risk
* Most Porto programs are Low or Medium risk
## Factors affecting rates
Stablecoin yields change based on:
* **Market demand** — When more people want to earn yield, rates increase
* **Blockchain network conditions** — Network activity affects yield availability
* **Economic conditions** — Central bank rates and monetary policy affect yields
* **Program changes** — Yield programs may adjust rates to manage supply
* **Competition** — Multiple programs competing for stablecoins can increase yields
Rates tend to be highest during high-demand periods and lowest during quiet market periods.
## Comparing programs for the same stablecoin
If multiple programs offer USDC or another stablecoin:
1. **Compare APRs** — Higher isn't always better if risk is higher
2. **Check lock periods** — Longer locks may offer higher yields but less flexibility
3. **Review smart contract risk** — Audited DeFi protocols are safer than new ones
4. **Consider convenience** — Direct Porto programs are most convenient
5. **Tax implications** — All programs are taxable; no difference there
For USDC, for example:
* **Circle Rewards (4.0% APR)** — No lock, integrated, lower risk
* **Aave (4.5% APR)** — 1-7 day lock, DeFi protocol, slightly higher risk
The Circle program offers simplicity and lower risk; Aave offers slightly higher yield with some withdrawal delay.
## Program changes and discontinuations
Porto regularly reviews yield programs. When rates change:
1. **Notification** — You'll see an in-app notification of rate changes
2. **No action required** — If your program is modified, rewards continue
3. **Discontinuation** — If a program ends, your coins aren't moved; rewards simply stop
4. **Alternative options** — Porto notifies you of alternative programs if one is discontinued
Stablecoins are not at risk even if a yield program ends — your coins remain safely in your vault.
## Estimating potential rewards
To estimate your annual rewards:
**Formula:** (Balance × APR) / 100 = Annual rewards
**Examples:**
* $10,000 USDC at 4.0% APR = $400/year (\$33/month)
* $100,000 USD at 5.0% APR = $5,000/year (\$417/month)
* $1,000,000 USDT at 3.5% APR = $35,000/year (\$2,917/month)
Keep in mind:
* This is gross yield; taxes apply to rewards
* Rates may change during the year
* Rewards are reinvested (they stay in your vault and earn rewards too if compounding is enabled)
## Tax reporting
Stablecoin rewards are ordinary income for tax purposes. Porto provides:
* **Transaction records** — All reward payments appear in your Activity log with dates
* **Download data** — You can export your reward history for tax filing
* **1099 integration** — Some organizations provide tax reporting forms
See [Stablecoin rewards and yield](/knowledge-base/porto/advanced/stablecoin-rewards) for tax implications details.
## Rates by program type
**Direct programs (lowest complexity):**
* Porto Direct Yield, Circle, Tether
* Rates: 3.0% - 5.5%
* Lock: None to minimal
* Risk: Low
* Best for: Simplicity, lowest risk, integrated with Porto
**DeFi programs (higher yield, more complexity):**
* Aave, Compound, Lido
* Rates: 3.5% - 6.0% (varies significantly)
* Lock: 1-7 days common
* Risk: Medium
* Best for: Users willing to accept smart contract risk for potentially higher yield
**Enterprise programs (custom terms):**
* Varies by organization
* Rates: Custom negotiated
* Lock: As agreed
* Risk: Varies
* Best for: Large organizations with negotiated rates
## How to switch between programs
If you want to move from one yield program to another:
1. **Find the new program** — Look in your vault settings for alternative programs
2. **Compare rates and terms** — Make sure the new program offers better rates/terms
3. **Disable current program** — Stop earning in the old program (coins remain in vault)
4. **Enable new program** — Enroll your balance in the new program
5. **Resume earning** — Rewards start accruing in the new program
No movement of coins is required — just enable a different program.
## Program selection guidance
**For maximum safety:**
* Choose Porto Direct Yield or Custodian programs (Circle, Tether)
* Accept slightly lower rates for maximum simplicity and safety
**For higher yields with moderate risk:**
* Choose established DeFi programs (Aave, Compound)
* Understand smart contract risk and withdrawal terms
* Start with smaller amounts if new to DeFi yield
**For institutional customers:**
* Work with your account manager on enterprise programs
* May offer custom rates and terms
* Higher minimums but often better yields
## Questions about rates
**Why do rates differ between programs?**
* Different programs have different costs and strategies
* Smart contract protocols have different risk levels
* Programs manage supply and demand differently
**Can rates ever go to zero?**
* Unlikely for major programs, but possible
* If a program ends, Porto notifies you and rewards stop
* Your coins remain safe — no downside to yields
**Are rates guaranteed?**
* No — APRs are subject to change
* Rates update based on market conditions
* Your agreement with Porto shows current rates and how changes are communicated
For specific questions about your organization's rates or programs, contact your Porto administrator or account manager.
# Verifying addresses
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/address-verification
Verify deposit address authenticity and integrity using Anchorage Digital's V1 and V2 signature schemes.
The addresses REST API endpoints return signatures of the address strings and other metadata that prove the address was generated by Anchorage Digital for your organization.
Verify the address signature and all accompanying metadata before using any address. This confirms authenticity and integrity.
## Signature schemes
The API supports two address verification schemes. Check the `signatureVersion` field to determine which applies.
| Scheme | How it works |
| ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **V1** | Verify signature against a fixed Ed25519 public key unique to your organization, distributed out-of-band by Anchorage Digital. Must be kept tamper-proof. |
| **V2** | Verify signature against the public key of the leaf certificate in an X.509 certificate chain returned with the response, then verify the chain against the Anchorage Digital Address Signing Root CA (hard-coded by the client). |
***
## V1 address signature verification
### Steps
1. **Verify the signature:**
* Decode `addressSignaturePayload` from hex to bytes.
* Decode `signature` from hex to bytes.
* Using your organization's fixed public key, verify that `signatureBytes` is a valid Ed25519 signature of `addressSignaturePayloadBytes`.
2. **Verify the signed address matches the address to be used:**
* Decode `addressSignaturePayload` from hex to bytes.
* Parse the bytes as JSON.
* Verify the address matches the `TextAddress` property in the JSON.
Validating the signature alone is insufficient. You must also confirm that `TextAddress` in the decoded payload matches the address you intend to use.
### V1 signed payload fields
| Field | Description |
| ------------- | ---------------------------------------- |
| `TextAddress` | The text format of the on-chain address. |
```json theme={null}
{
"TextAddress": "2N19AcihQ1a4MxQW658UFHTioUNnMkiHPkw"
}
```
### Sample V1 validation code
```go theme={null}
package main
import (
"crypto/ed25519"
"encoding/hex"
"encoding/json"
"fmt"
)
// V1SignedPayload represents the JSON structure in the addressSignaturePayload for V1 signatures
type V1SignedPayload struct {
TextAddress string `json:"TextAddress"`
}
// verifyV1AddressSignature verifies a V1 address signature.
//
// Parameters:
// - address: The address string from the API response
// - addressSignaturePayload: Hex-encoded bytes that were signed
// - signature: Hex-encoded Ed25519 signature
// - orgPublicKeyHex: Hex-encoded Ed25519 public key for your organization (obtained out-of-band)
//
// Returns an error if verification fails.
func verifyV1AddressSignature(address, addressSignaturePayload, signature, orgPublicKeyHex string) error {
// Step 1: Check the validity of the signature
// Decode the addressSignaturePayload from hex to bytes
payloadBytes, err := hex.DecodeString(addressSignaturePayload)
if err != nil {
return fmt.Errorf("failed to decode addressSignaturePayload: %w", err)
}
// Decode the signature from hex to bytes
signatureBytes, err := hex.DecodeString(signature)
if err != nil {
return fmt.Errorf("failed to decode signature: %w", err)
}
// Decode the organization public key from hex
publicKeyBytes, err := hex.DecodeString(orgPublicKeyHex)
if err != nil {
return fmt.Errorf("failed to decode organization public key: %w", err)
}
if len(publicKeyBytes) != ed25519.PublicKeySize {
return fmt.Errorf("invalid public key size: got %d bytes, expected %d", len(publicKeyBytes), ed25519.PublicKeySize)
}
publicKey := ed25519.PublicKey(publicKeyBytes)
// Verify the Ed25519 signature
if !ed25519.Verify(publicKey, payloadBytes, signatureBytes) {
return fmt.Errorf("signature verification failed")
}
// Step 2: Verify the signed address matches the address to be used
// Parse the payload bytes as JSON
var signedPayload V1SignedPayload
if err := json.Unmarshal(payloadBytes, &signedPayload); err != nil {
return fmt.Errorf("failed to parse signed payload: %w", err)
}
// Verify the TextAddress matches
if signedPayload.TextAddress != address {
return fmt.Errorf("signed TextAddress does not match: signed=%q, expected=%q", signedPayload.TextAddress, address)
}
return nil
}
func main() {
// Sample API response data
address := "2N19AcihQ1a4MxQW658UFHTioUNnMkiHPkw"
addressSignaturePayload := "7b225465787441646472657373223a22324e313941636968513161344d78515736353855464854696f554e6e4d6b6948506b77227d"
signature := "b18f6848dc0fef01a069e7ac26046383bf5cd130203994dc2d72b5a9097351b1e8b67115b63124fbc8c16673566416a635913c670b676089339c62a7824baa03"
// Organization public key - obtained out-of-band from Anchorage Digital beforehand
// Unique per Organization, fixed for the lifetime of that Organization
// Must be kept tamper-proof
orgPublicKeyHex := "8a88e3dd7409f195fd52db2d3cba5d72ca6709bf1d94121bf3748801b40f6f5c"
// Verify the signature
if err := verifyV1AddressSignature(address, addressSignaturePayload, signature, orgPublicKeyHex); err != nil {
fmt.Printf("✗ V1 Address signature verification failed: %v\n", err)
return
}
fmt.Println("✓ V1 Address signature verified successfully!")
fmt.Printf(" Address: %s\n", address)
fmt.Println("\nYou may now safely use this address for deposits.")
}
```
***
## V2 address signature verification
Addresses with `signatureVersion: V2` include a `certChain` field containing an X.509 certificate chain in PEM format.
### Steps
1. **Verify the certificate chain:**
* Parse `certChain` as PEM-encoded X.509 certificates.
* Verify the chain from the leaf to the trusted Anchorage Digital Root CA.
* Verify all certificates are temporally valid (both `notAfter` and `notBefore`).
* Verify the leaf certificate's Subject Alternative Names include `address-provider.anchorage.internal`.
* Verify the leaf certificate's `KeyUsage` includes both `digitalSignature` and `nonRepudiation` (also known as `contentCommitment`).
* Extract the public key from the leaf certificate. Currently only Ed25519 keys are supported, but this may change.
The leaf certificate is at index 0, followed by zero or more intermediates. The root cert is excluded from the response. The number of certificates in the chain may change. Follow standard X.509 verification procedures — not all libraries perform all checks by default.
2. **Verify the signature:**
* Decode `addressSignaturePayload` from hex to bytes.
* Decode `signature` from hex to bytes.
* Using the leaf certificate's public key, verify `signatureBytes` is a valid signature of the payload bytes.
3. **Verify the signed details:**
* Parse `addressSignaturePayload` bytes as JSON.
* Verify `SignatureExpiresAt` ≥ current UTC Unix timestamp.
* Verify `TextAddress` matches the address to be used.
* Verify `VaultId` matches your expected Vault ID.
* Verify `NetworkId` matches the expected network for this address.
`NetworkName` is included for human readability and does not need to be verified. Do not use a "strict" JSON parser that rejects extra properties — future versions may add fields.
Anchorage Digital periodically refreshes V2 signatures and the Address Signing Root CA before expiration. The deposit address itself will not change — only the signature, certificate chain, and Root CA are updated.
### V2 signed payload fields
| Field | Description |
| -------------------- | ------------------------------------------------------------- |
| `TextAddress` | The text format of the on-chain address. |
| `VaultId` | Identifies the vault this address belongs to. |
| `NetworkId` | Identifies the network this address can receive deposits on. |
| `NetworkName` | Human-readable version of `NetworkId`. |
| `SignatureExpiresAt` | Unix timestamp after which the signature must not be trusted. |
```json theme={null}
{
"VaultId": "dae6089e7c0836705f0562af0f1e4e1f",
"TextAddress": "bcrt1q709skemgf5skpsnysvgme2s3ztehkutl390yl0wp29lnmum5uw7qg0qrwm",
"NetworkName": "Bitcoin Regnet",
"NetworkId": "BTC_R",
"SignatureExpiresAt": 1769450713
}
```
### Anchorage Digital Address Signing Root CAs
Hard-code the appropriate Root CA for the environment you are targeting. This value must be tamper-proof.
```
-----BEGIN CERTIFICATE-----
MIIBXTCCAQ+gAwIBAgIUQZI+MSvYTXQHra+3OAKnwAMzotUwBQYDK2VwMCAxHjAc
BgNVBAMMFWNhLmFuY2hvcmFnZS5pbnRlcm5hbDAeFw0yNjAxMjYwMDAwMDBaFw0y
NzAxMjYwMDAwMDBaMCAxHjAcBgNVBAMMFWNhLmFuY2hvcmFnZS5pbnRlcm5hbDAq
MAUGAytlcAMhADTh1nctgIHtAKNW8ww/bY606pJ3OP2dyZYcQrU2kG5jo1swWTAP
BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwICBDAUBgorBgEEAYaNHwEBBAYW
BHJvb3QwIAYDVR0RBBkwF4IVY2EuYW5jaG9yYWdlLmludGVybmFsMAUGAytlcANB
ANkkdudEjH9RTKbRAxrRXyMSS/TgmdSrAVYOZzoRDJlyc+5oD+a0pmmwWVe86xZi
37YbN1GzVlXcJAPpV6ceEQU=
-----END CERTIFICATE-----
```
```
-----BEGIN CERTIFICATE-----
MIIBXDCCAQ6gAwIBAgITOfTQ4rYUsghgvdl8YCJSC67uGDAFBgMrZXAwIDEeMBwG
A1UEAwwVY2EuYW5jaG9yYWdlLmludGVybmFsMB4XDTI2MDEyNDAwMDAwMFoXDTI3
MDEyNDAwMDAwMFowIDEeMBwGA1UEAwwVY2EuYW5jaG9yYWdlLmludGVybmFsMCow
BQYDK2VwAyEAPlBo2/+kPPL0WRpT+B/yHsU25AN/M6HP2bzC61yHb4ajWzBZMA8G
A1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgIEMBQGCisGAQQBho0fAQEEBhYE
cm9vdDAgBgNVHREEGTAXghVjYS5hbmNob3JhZ2UuaW50ZXJuYWwwBQYDK2VwA0EA
YsJxVI9n42liCF9f+Ou7uuC1QGFwaHwFsfOm0WFofSlE1trWqzj4ruzjPYSRJc8H
t2A7XCAfXkG0mzKpL/wQDg==
-----END CERTIFICATE-----
```
### Sample V2 validation code
```go theme={null}
package main
import (
"crypto/ed25519"
"crypto/x509"
"encoding/hex"
"encoding/json"
"encoding/pem"
"fmt"
"time"
)
// V2SignedPayload represents the JSON structure in the addressSignaturePayload for V2 signatures
type V2SignedPayload struct {
TextAddress string `json:"TextAddress"`
VaultId string `json:"VaultId"`
NetworkId string `json:"NetworkId"`
NetworkName string `json:"NetworkName"`
SignatureExpiresAt int64 `json:"SignatureExpiresAt"` // Unix timestamp
}
// verifyV2AddressSignature verifies a V2 address signature.
//
// Parameters:
// - now: The "current" time. Note that conforming implementations must use
// a trusted source for the current time.
// - address: The address string from the API response
// - addressSignaturePayload: Hex-encoded bytes that were signed
// - signature: Hex-encoded signature
// - certChainPEM: PEM-encoded certificate chain (leaf first, then intermediates)
// - rootCAPEM: PEM-encoded Root CA certificate (hard-coded by client)
// - expectedVaultId: Your Vault ID to verify against the signed VaultId
// - expectedNetworkId: Expected network ID for this address (e.g., "BTC", "ETH")
//
// Returns an error if verification fails.
func verifyV2AddressSignature(
now time.Time,
address, addressSignaturePayload, signature, certChainPEM, rootCAPEM, expectedVaultId, expectedNetworkId string,
) error {
// Step 1: Verify the certificate chain
// Parse the certificate chain from PEM
certs, err := parsePEMCertificates([]byte(certChainPEM))
if err != nil {
return fmt.Errorf("failed to parse certificate chain: %w", err)
}
if len(certs) == 0 {
return fmt.Errorf("certificate chain is empty")
}
leafCert := certs[0]
var intermediateCerts []*x509.Certificate
if len(certs) > 1 {
intermediateCerts = certs[1:]
}
// Parse the Root CA
rootCACerts, err := parsePEMCertificates([]byte(rootCAPEM))
if err != nil {
return fmt.Errorf("failed to parse Root CA: %w", err)
}
if len(rootCACerts) != 1 {
return fmt.Errorf("expected exactly one Root CA certificate, got %d", len(rootCACerts))
}
rootCA := rootCACerts[0]
// Verify the leaf certificate's KeyUsage includes both
// digitalSignature and nonRepudiation (AKA contentCommitment)
if leafCert.KeyUsage&x509.KeyUsageDigitalSignature == 0 {
return fmt.Errorf("leaf certificate KeyUsage missing DigitalSignature")
}
if leafCert.KeyUsage&x509.KeyUsageContentCommitment == 0 {
return fmt.Errorf("leaf certificate KeyUsage missing NonRepudiation (ContentCommitment)")
}
// Verify the certificate chain from leaf to Root CA
roots := x509.NewCertPool()
roots.AddCert(rootCA)
intermediates := x509.NewCertPool()
for _, cert := range intermediateCerts {
intermediates.AddCert(cert)
}
// NOTE: Not all x509 libraries are created equal and are not
// guaranteed to verify exactly the same things!
//
// Always review the library you plan to use and ensure it covers the
// checks described in the User Guide!
//
// For example, the Go implementation checks all Certificates for
// temporal validity (notBefore and notAfter against CurrentTime), for
// valid signatures up the chain, and checks that the Subject
// Alternative Names include the values in DNSNames below.
//
// However it does not check the KeyUsage bits, hence the additional
// checks above.
opts := x509.VerifyOptions{
DNSNames: []string{"address-provider.anchorage.internal"},
Roots: roots,
Intermediates: intermediates,
CurrentTime: now,
// NOTE: This allows for any Extended Key Usage, but does not
// check the Key Usage bits, hence the additional checks above.
KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageAny},
}
if _, err := leafCert.Verify(opts); err != nil {
return fmt.Errorf("certificate chain verification failed: %w", err)
}
// Extract the public key from the leaf certificate
leafPublicKey, ok := leafCert.PublicKey.(ed25519.PublicKey)
if !ok {
return fmt.Errorf("leaf certificate does not use Ed25519 (got type %T)", leafCert.PublicKey)
}
// Step 2: Verify the signature
// Decode the addressSignaturePayload from hex to bytes
payloadBytes, err := hex.DecodeString(addressSignaturePayload)
if err != nil {
return fmt.Errorf("failed to decode addressSignaturePayload: %w", err)
}
// Decode the signature from hex to bytes
signatureBytes, err := hex.DecodeString(signature)
if err != nil {
return fmt.Errorf("failed to decode signature: %w", err)
}
// Verify the signature using the leaf certificate's public key
if !ed25519.Verify(leafPublicKey, payloadBytes, signatureBytes) {
return fmt.Errorf("signature verification failed")
}
// Step 3: Verify the signed details
// Parse the payload bytes as JSON
var signedPayload V2SignedPayload
if err := json.Unmarshal(payloadBytes, &signedPayload); err != nil {
return fmt.Errorf("failed to parse signed payload: %w", err)
}
// Verify SignatureExpiresAt is not in the past
if now.Unix() > signedPayload.SignatureExpiresAt {
expiryTime := time.Unix(signedPayload.SignatureExpiresAt, 0)
return fmt.Errorf("signature has expired at %s", expiryTime)
}
// Verify TextAddress matches
if signedPayload.TextAddress != address {
return fmt.Errorf("signed TextAddress does not match: signed=%q, expected=%q",
signedPayload.TextAddress, address)
}
// Verify VaultId matches
if signedPayload.VaultId != expectedVaultId {
return fmt.Errorf("signed VaultId does not match: signed=%q, expected=%q",
signedPayload.VaultId, expectedVaultId)
}
// Verify NetworkId matches
if signedPayload.NetworkId != expectedNetworkId {
return fmt.Errorf("signed NetworkId does not match: signed=%q, expected=%q",
signedPayload.NetworkId, expectedNetworkId)
}
return nil
}
// parsePEMCertificates parses PEM-encoded certificates and returns them as a slice
func parsePEMCertificates(pemData []byte) ([]*x509.Certificate, error) {
var certs []*x509.Certificate
for {
block, rest := pem.Decode(pemData)
if block == nil {
break
}
if block.Type != "CERTIFICATE" {
pemData = rest
continue
}
cert, err := x509.ParseCertificate(block.Bytes)
if err != nil {
return nil, fmt.Errorf("failed to parse certificate: %w", err)
}
certs = append(certs, cert)
pemData = rest
}
return certs, nil
}
func main() {
// Sample API response data
address := "bcrt1q709skemgf5skpsnysvgme2s3ztehkutl390yl0wp29lnmum5uw7qg0qrwm"
addressSignaturePayload := "7b225661756c744964223a226461653630383965376330383336373035663035363261663066316534653166222c225465787441646472657373223a22626372743171373039736b656d676635736b70736e797376676d653273337a7465686b75746c333930796c30777032396c6e6d756d357577377167307172776d222c224e6574776f726b4e616d65223a22426974636f696e205265676e6574222c224e6574776f726b4964223a224254435f52222c225369676e6174757265457870697265734174223a313736393435303731337d"
signature := "951eb2fb560e660aa9c3d1ccd120d3ad1a19d90d8747347057e48bf174330eb386089e3232d822fd66b8183cce8059c91183afde299b920a0e0c05c5b167360e"
certChainPEM := `-----BEGIN CERTIFICATE-----
MIIBYTCCAROgAwIBAgIUMLKt+K9eFku+P7BbefE1xAHg0hcwBQYDK2VwMAAwHhcN
MjYwMTI2MTcwNDEzWhcNMjcwMTI2MTcwNTEzWjAuMSwwKgYDVQQDEyNhZGRyZXNz
LXByb3ZpZGVyLmFuY2hvcmFnZS5pbnRlcm5hbDAqMAUGAytlcAMhAPsgM70aWFYs
ZaLHawtYJpl42BkiTLyCq96+OXe4FxrVo3EwbzAOBgNVHQ8BAf8EBAMCBsAwDAYD
VR0TAQH/BAIwADAfBgNVHSMEGDAWgBS0usSFeB2gjC+wcowtxN3MeKSH7zAuBgNV
HREEJzAlgiNhZGRyZXNzLXByb3ZpZGVyLmFuY2hvcmFnZS5pbnRlcm5hbDAFBgMr
ZXADQQCXmvIkuPnUgCHxWmFmzvgWdv9lUlt84oZCel+OeJW9n8PR88tGxAcD1E3+
KDBXVpO0GcRA0W9+xqqICAo2ROEJ
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIBKDCB26ADAgECAhRGsD05KldIse+uIEa976AijTqlxjAFBgMrZXAwADAeFw0y
NjAxMjYxNzA0MTNaFw0yNzAxMjYxNzA1MTNaMAAwKjAFBgMrZXADIQCNpyY5Sr21
FHNvvLkBKG8AEMKdhqtajmV5d2QaZlmtAqNnMGUwDgYDVR0PAQH/BAQDAgIEMBIG
A1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFLS6xIV4HaCML7ByjC3E3cx4pIfv
MCAga1UdEQEB/wQWMBSCEmFuY2hvcmFnZS5pbnRlcm5hbDAFBgMrZXADQQCIgw6k
LMIwhd3ACjG03cJ5z/ZZp8aXXycFq2ZC9TLhieJ3rncyMH6ZdyJ3Ai1eVaHs4vn
DCv54Vdh83vvSky4K
-----END CERTIFICATE-----
`
// NOTE: This is a FAKE Root CA used just for this example.
// NOTE: Conforming client implementations should hard-code the real
// Anchorage Digital Address Signing Root CA for the environment they
// are making requests to.
rootCAPEM := `-----BEGIN CERTIFICATE-----
MIIBGzCBzqADAgECAhQ2qQwArneTuF0dbNDs8i/ExuyW2DAFBgMrZXAwADAeFw0y
NjAxMjYxNzA0MTNaFw0yNzAxMjYxNzA1MTNaMAAwKjAFBgMrZXADIQB+gEnytXKn
uAMonIWGWnB0qyTqa0aw3l9u5VRbu86UgaNaMFgwDgYDVR0PAQH/BAQDAgIEMA8G
A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFOj64tL1teJHkojsiblnnK34Tw+EMBYGN
A1UdEQEB/wQMMAqCCGludGVybmFsMAUGAytlcANBAAg2IcVEXmWKSivhUNSatNfM
mASxi83QscIuyP/sIW2sRIuCqQJoo9lN6TaxzyV62cQMzthFOCZcgRE+k0JV7Ao=
-----END CERTIFICATE-----
`
// Your Vault ID - obtained from your application context
expectedVaultId := "dae6089e7c0836705f0562af0f1e4e1f"
// Expected network ID for this address
expectedNetworkId := "BTC_R"
// Implementations should use the actual current time
// now := time.Now()
now := time.Unix(1769450600, 0) // Fake time so that this example passes.
// Verify the signature
if err := verifyV2AddressSignature(
now,
address,
addressSignaturePayload,
signature,
certChainPEM,
rootCAPEM,
expectedVaultId,
expectedNetworkId,
); err != nil {
fmt.Printf("✗ V2 Address signature verification failed: %v\n", err)
return
}
fmt.Println("✓ V2 Address signature verified successfully!")
fmt.Printf(" Address: %s\n", address)
fmt.Printf(" Vault ID: %s\n", expectedVaultId)
fmt.Printf(" Network: %s\n", expectedNetworkId)
fmt.Println("\nYou may now safely use this address for deposits.")
}
```
# Authentication
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/authentication
Authenticate Anchorage Digital API requests with API keys and signatures.
All API requests require the `Api-Access-Key` header.
```http theme={null}
Api-Access-Key: YOUR_API_KEY
```
Some endpoints also require:
```http theme={null}
Api-Timestamp: 1577880000
Api-Signature: 4bf42054bf7db1f8...
```
For how permission groups, keys, and signatures work together, see [API setup](/knowledge-base/porto/developers/setting-up) and [Request signing](/knowledge-base/porto/developers/request-signing).
## How authentication works
API authentication has three layers. Every request needs all the layers that apply to the endpoint you're calling.
A permission group defines which vaults a key can access and what operations it can perform.
An access key identifies the caller and is required on every request.
An Ed25519 signature authorizes sensitive endpoints, such as withdrawals.
# API Changelog
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/changelog
Subscribe to Anchorage API updates, additions, and breaking changes.
[2026](/knowledge-base/porto/api-reference/changelog) · [2025](/knowledge-base/api-reference/changelog-2025) · [2024](/knowledge-base/api-reference/changelog-2024)
## Added Stablecoin Reserves Endpoints
**Added** two new endpoints to the Stablecoins API for retrieving reserve information.
**Category**: Stablecoins
**Endpoints Added**:
* `GET /stablecoins/reserves`: Retrieves the history of stablecoin reserves.
* `GET /stablecoins/reserves/entitled-stablecoins`: Gets a list of stablecoins for which the organization is entitled to view reserves.
**Impact**: These new endpoints allow users to programmatically access stablecoin reserve data and history.
## Improved Response Structure for the List Tags Endpoint
**Improved** The response body for the `GET /tags` endpoint now nests the list of tags within a `data` object for consistency with other API endpoints.
**Category**: Tagging
**Endpoint Changed**:
* `GET /tags`: Returns the list of tags nested under a `data` object instead of at the top level.
**Impact**: This is a breaking change. Integrations must be updated to read the list of tags from `response.data.tags` instead of the top-level `response.tags`.
**Example**:
*Previous Response Structure:*
```json theme={null}
{
"tags": [
{
"name": "urgent",
"tagType": "client"
}
]
}
```
*New Response Structure:*
```json theme={null}
{
"data": {
"tags": [
{
"name": "urgent",
"tagType": "client"
}
]
}
}
```
## Improved Field Naming for Creating Wallets on Compatible Networks
**Improved** The `createOnAllCompatibleNetworks` field for creating wallets has been renamed to `activateAllCompatibleNetworks`.
**Category**: Wallets
**Endpoint Changed**:
* `POST /vaults/{vaultId}/wallets`: The `createOnAllCompatibleNetworks` boolean property was removed and replaced by `activateAllCompatibleNetworks`.
**Impact**: This is a breaking change. Integrations using `createOnAllCompatibleNetworks` must switch to `activateAllCompatibleNetworks` to avoid request failures. The field's behavior is unchanged: when set to `true`, it activates the new wallet on every network that is key-compatible with the primary `networkId` and enabled for your organization.
## Improved Wallet Creation and Activation Across Compatible Networks
**Improved** wallet creation and activation to support all compatible networks with a single flag.
**Category**: Wallets
**Endpoints Changed**:
* `POST /vaults/{vaultId}/wallets`: Accepts a new optional boolean parameter, `createOnAllCompatibleNetworks`.
* `POST /wallets/{walletId}/activate`: Accepts a new optional boolean parameter, `activateAllCompatibleNetworks`.
**Impact**: This provides a more efficient way to manage wallets across multiple networks. Instead of listing every compatible network ID, you can use a single boolean flag to create or activate a wallet on all available compatible networks for your organization. The new `...AllCompatibleNetworks` parameters are mutually exclusive with the existing `compatibleNetworkIds` parameter, so you must provide exactly one of them.
## Added Endpoints for Tag Management
**Added** a new Tags API to create, list, and manage tags for entities.
**Category**: Tags
**Endpoints Added**:
* `GET /tags`: Lists tags.
* `POST /tags`: Creates a tag.
* `POST /tags/apply`: Applies tags to an entity.
* `DELETE /tags/apply/{entityId}/{tagName}`: Removes a tag from an entity.
* `GET /tags/search`: Searches for entities by tag.
**Impact**: This introduces a new feature for users to programmatically organize, categorize, and search for their resources using tags.
## Improved Asset Type Details with Compatible Network IDs
**Improved** The `GET /asset-types` endpoint response now includes a list of compatible network IDs.
**Category**: Asset Types
**Endpoint Changed**:
* `GET /asset-types`: The `AssetTypeDetails` object now contains `compatibleNetworkIds`, an array of network IDs that share wallet key derivation with the asset's primary network.
**Impact**: This helps you identify which networks can be used when creating a new wallet or activating an existing wallet on additional networks.
**Example**:
```json theme={null}
{
"data": [
{
"assetType": "ETH",
"name": "Ethereum",
"decimals": 18,
"networkId": "ETH",
"onchainIdentifier": null,
"featureSupport": [
"TRANSFERS",
"HOLDS"
],
"compatibleNetworkIds": [
"POLYGON",
"AVAX_C"
]
}
]
}
```
## Added Tax Lot Selection for Async Orders
**Added** the ability to specify a tax lot ID for async sell orders for tax reporting.
**Category**: Trading
**Endpoints Changed**:
* `POST /trading/async-order`: Accepts a new optional `specLotId` field to specify a tax lot to retire for `SELL` orders with a `timeInForce` of `FOK`; the `rejectReason` field in the response now includes `InvalidSideForSpecLotID` and `InvalidTimeInForceForSpecLotID`.
* `POST /trading/async-order/cancel`: The `rejectReason` field in the response now includes `InvalidSideForSpecLotID` and `InvalidTimeInForceForSpecLotID`.
**Impact**: You can now programmatically manage tax lot retirement for specific `SELL` orders, enhancing tax reporting capabilities.
## Improved Collateral Package Endpoint with Value and Price Details
**Improved** The response for the collateral packages endpoint now includes additional value and pricing details for each package and its underlying assets.
**Category**: Collateral Management
**Endpoint Changed**:
* `GET /collateral_management/packages`: The response now includes optional `exposureValue` and `packageValue` fields at the top level of each package, plus `price`, `quantity`, and `weightedValue` for each asset in the `collateralAssets` array.
**Impact**: This is a non-breaking change that gives you a more complete financial overview of each collateral package directly in the list view.
**Example**:
```json theme={null}
{
"data": [
{
"packageId": "unique-package-id",
"clientReferenceId": "client-ref-123",
"active": true,
"exposureValue": "50000.00",
"packageValue": "100000.00",
"collateralAssets": [
{
"asset": {
"assetType": "BTC",
"type": "ANCHORAGECUSTODY"
},
"price": "60000.00",
"quantity": "1.5",
"weight": "0.9",
"weightedValue": "81000.00"
}
],
// ... other fields
}
],
"page": {
"next": null
}
}
```
## Added Endpoint to Request Collateral Decrease
**Added** a new endpoint that lets users request a collateral decrease for a specified collateral package.
**Category**: Collateral Management
**Endpoint Added**:
* `POST /collateral_management/packages/{packageId}/collateral-decrease`: Initiates a two-way Atlas settlement to return assets from the secured party's collateral wallets to the pledgor's return wallets.
**Impact**: This lets either the pledgor or the secured party programmatically initiate the return of collateral assets. A successful call creates an Atlas settlement, and the `settlementId` is returned in the response for tracking.
**Example**:
```json theme={null}
{
"assetAmounts": [
{ "assetTypeID": "BTC", "value": "1.1" },
{ "assetTypeID": "ETH", "value": "20.62" }
],
"idempotencyKey": "decrease-2024-01-15-pkg-abc",
"useGasStation": false
}
```
## Added Endpoint to Activate Wallets on Additional Networks
**Added** a new endpoint to activate an existing wallet on additional compatible networks.
**Category**: Wallets
**Endpoint Added**:
* `POST /wallets/{walletId}/activate`: Activates an existing wallet on additional compatible networks.
**Impact**: This lets you enable a single wallet for use across multiple networks that share the same key family, streamlining asset management without needing to create separate wallets.
## Added Fiat Details to Transaction Responses
**Added** A new `fiatDetails` object is now included in transaction responses to provide banking details for fiat transactions.
**Category**: Transactions
**Endpoints Changed**:
* `GET /transactions`: The response now includes a `fiatDetails` object for fiat-related transactions.
* `GET /transactions/{transactionId}`: The response now includes a `fiatDetails` object for fiat-related transactions.
**Impact**: This provides key banking information, such as account number, bank name, and FedWire number, which aids in reconciliation and tracking.
**Example**:
```json theme={null}
"fiatDetails": {
"accountNumber": "123456789",
"bankId": "987654321",
"bankName": "Anchorage Digital Bank",
"fedWire": "WIRE12345",
"memo": "Q1 Payout",
"name": "Jane Doe"
}
```
## Added Endpoint to List All Subaccounts
**Added** a new endpoint to retrieve all subaccounts associated with an organization.
**Category**: Subaccounts
**Endpoint Added**:
* `GET /subaccounts/customers/accounts`: Lists all subaccounts for your organization, with filtering by `subaccountIds`, `externalIds`, `endDate`, and `statuses`, plus pagination via `afterId` and `limit`.
**Impact**: This provides a comprehensive, organization-level view of all subaccounts, enabling more efficient and complete data retrieval than fetching subaccounts on a per-customer basis.
## Improved Transfers and Withdrawals with Trusted Destination Support
**Improved** Transfers and withdrawals can now use a Trusted Destination as the destination, and wallet responses can reflect it as a resource type.
**Category**: Transfers, Transactions, Wallets
**Endpoints Changed**:
* `POST /transactions/withdrawal`: Accepts `TRUSTED_DESTINATION` as a `destination.type` value.
* `POST /transfers`: Accepts `TRUSTED_DESTINATION` as a `destination.type` value.
* `GET /transfers`: Can return `TRUSTED_DESTINATION` as a destination type in the response.
* `GET /transfers/{transferId}`: Can return `TRUSTED_DESTINATION` as a destination type in the response.
* `GET /vaults/{vaultId}/wallets`: Can return `TRUSTED_DESTINATION` as a wallet resource type.
* `POST /vaults/{vaultId}/wallets`: Can return `TRUSTED_DESTINATION` as a wallet resource type.
* `GET /wallets`: Can return `TRUSTED_DESTINATION` as a wallet resource type.
* `GET /wallets/{walletId}`: Can return `TRUSTED_DESTINATION` as a wallet resource type.
**Impact**: This simplifies withdrawal and transfer workflows. You can send funds to a pre-configured Trusted Destination by providing its ID, without needing to re-specify address details, memos, or destination tags in each API call. Using Trusted Destinations also reduces the risk of sending funds to an incorrect address.
**Example**:
```json theme={null}
{
"assetType": "XRP",
"amount": "100.00",
"source": {
"id": "1c920f4241b78a1d483a29f3c24b6c4c",
"type": "WALLET"
},
"destination": {
"id": "your_trusted_destination_id",
"type": "TRUSTED_DESTINATION"
}
}
```
## Removed Wallet Activation Endpoint
**Removed** The endpoint for activating an existing wallet on additional compatible networks has been removed.
**Category**: Wallets
**Endpoint Removed**:
* `POST /wallets/{walletId}/activate`
**Impact**: You can no longer programmatically activate an existing wallet on additional compatible networks.
## Added Endpoint to Activate Wallets on Additional Networks
**Added** a new endpoint to activate an existing wallet on additional compatible networks.
**Category**: Wallets
**Endpoint Added**:
* `POST /wallets/{walletId}/activate`: Activates an existing wallet on additional compatible networks that share the same key family, without creating a new wallet.
**Impact**: This lets you enable a single wallet for use across multiple networks that share the same key family, streamlining asset management by reusing a single wallet instead of creating a new one for each network.
## Added Endpoint for Collateral Decrease Requests
**Added** a new endpoint that lets users request a collateral decrease.
**Category**: Collateral Management
**Endpoint Added**:
* `POST /collateral_management/packages/{packageId}/collateral-decrease`: Enables programmatic requests to decrease collateral for a specified package.
**Impact**: This lets you programmatically initiate a decrease in collateral for a specific package.
## Added Compatible Networks Support to Wallet Creation
**Added** an optional `compatibleNetworkIds` field for activating a new wallet on additional compatible networks at the time of creation.
**Category**: Wallets
**Endpoint Changed**:
* `POST /vaults/{vaultId}/wallets`: Accepts a new optional `compatibleNetworkIds` field (an array of strings).
**Impact**: This lets you create a wallet and activate it on multiple compatible networks in a single API call. All specified networks must share the same key family as the primary `networkId`, and activation happens synchronously after wallet creation.
**Example**:
```json theme={null}
{
"networkId": "ETH",
"walletName": "My EVM Wallet",
"compatibleNetworkIds": [
"POLYGON",
"AVAX"
]
}
```
## Improved Memo Handling for Fiat Trusted Destinations
**Improved** The behavior of the `memo` field for fiat transfers and withdrawals to Trusted Destinations has been clarified.
**Category**: Transactions, Transfers, and Trusted Destinations
**Endpoints Changed**:
* `POST /transactions/withdrawal`: The `memo` field within `assetParametersFiatTrustedDestination` is now optional; if omitted, the default memo from the saved Trusted Destination is used.
* `POST /transfers`: The `memo` field within `assetParametersFiatTrustedDestination` is now optional; if omitted, the default memo from the saved Trusted Destination is used.
* `GET /trusted_destinations`: The response now specifies that the `memo` for a fiat destination has a maximum length of 140 characters.
**Impact**: This simplifies API calls by letting you rely on the pre-configured memo on a Trusted Destination, reducing the need to specify it in every withdrawal or transfer request.
## Improved Stablecoin History Response Field Naming
**Improved** In the response for the stablecoin history endpoint, the `issueRedeemId` field has been renamed to `id`.
**Category**: Stablecoins
**Endpoint Changed**:
* `GET /stablecoins/history`: The unique identifier for an issue or redeem operation is now returned as `id` instead of `issueRedeemId`.
**Impact**: This is a breaking change. Integrations that parse `issueRedeemId` must switch to the new `id` field.
**Example**:
*Before:*
```json theme={null}
{
"data": [
{
"issueRedeemId": "b1a1c1...",
"operationType": "ISSUE",
...
}
]
}
```
*After:*
```json theme={null}
{
"data": [
{
"id": "b1a1c1...",
"operationType": "ISSUE",
...
}
]
}
```
## Improved Stablecoin History Endpoint Pagination and Status Detail
**Improved** The stablecoin history response now aligns with the standard paginated format and includes more detailed status information.
**Category**: Stablecoins
**Endpoint Changed**:
* `GET /stablecoins/history`: The response now returns a `data` array plus a `page` object for pagination (replacing `hasNextPage`), adds `destinationOperationId` and `sourceOperationId`, adds a `status` field (`INITIATED`, `EXECUTING`, `COMPLETED`, `FAILED`, `UNKNOWN`), adds an optional `subStatus` field, and expands `operationType` to include `BRIDGE` and `SWAP`.
**Impact**: This is a breaking change. The `conversions` array is now nested under `data`, and pagination uses a `page.next` URL instead of the previous `hasNextPage` boolean. Integrations must be updated to parse the new response structure.
**Example**:
```json theme={null}
{
"data": [
{
"issueRedeemId": "...",
"operationType": "ISSUE",
"status": "COMPLETED",
"subStatus": null,
"sourceAssetTypeId": "USD",
"destinationAssetTypeId": "USDC",
"amount": "100.00",
"sourceOperationId": "...",
"destinationOperationId": "..."
}
],
"page": {
"next": "/v2/stablecoins/history?..."
}
}
```
## Improved Order Type Support with LIMIT\_ALL\_IN
**Improved** Added `LIMIT_ALL_IN` as a new possible enum value for the `orderType` field in trading order responses.
**Category**: Trading
**Endpoints Changed**:
* `GET /trading/orders`: The `orderType` field in the response may now include `LIMIT_ALL_IN`.
* `GET /trading/orders/{orderId}`: The `orderType` field in the response may now include `LIMIT_ALL_IN`.
**Impact**: Responses from the list orders and get order by ID endpoints may now include `LIMIT_ALL_IN` as an `orderType`. Make sure your client can handle this new value.
## Improved Statements with Correction Timestamps and Filtering
**Improved** Added filtering and timestamp information for corrected statements, so you can track and query statements updated after their initial generation.
**Category**: Statements
**Endpoints Changed**:
* `GET /statements`: Accepts two new optional query parameters, `correctedAfter` and `correctedBefore`, to filter for statements corrected at or after or before a given time.
* `GET /statements/{statementId}`: The response now includes a `correctedAt` field indicating when a correction was made.
**Impact**: You can now programmatically identify and filter for statements that have been corrected, improving audit and reconciliation workflows.
**Example**:
```json theme={null}
{
"data": {
"customerId": "fbcdb420fca4439d919089e60d59cd5b12b692d215694681b636bffb6cb1618c",
"createdAt": "2025-09-01T00:47:16.937934Z",
"correctedAt": "2025-09-15T10:00:00.000000Z",
"displayName": "ETF Statement September 2025",
"id": "8de0fc33-7443-4dcf-bbf1-4ca8d0e0509f",
"typeId": "058da362-31a7-4e2b-ae3e-77b095389a5f"
}
}
```
## Added Subaccount ID Filter for Deposit Attributions
**Added** You can now filter deposit attributions by one or more `subaccountIds`.
**Category**: Deposit Attribution
**Endpoint Changed**:
* `GET /deposit-attributions/attributions`: Accepts a new query parameter, `subaccountIds`.
**Impact**: This allows for more granular filtering of deposit attributions, making it easier to retrieve records associated with specific subaccounts.
**Example**: `GET /v2/deposit-attributions/attributions?subaccountIds=subaccount_id_1,subaccount_id_2`
## Improved Permission Requirements for Stablecoin History
**Improved** permission requirements for the stablecoin history endpoint.
**Category**: Stablecoins
**Endpoint Changed**:
* `GET /stablecoins/history`: Now uses the more specific `Read Stablecoin Conversions` permission as the primary requirement.
**Impact**: For backward compatibility, the endpoint continues to accept the older `Read vault activity` permission too, so no immediate changes are required for existing integrations.
## Added Stablecoin Conversion History Endpoint
**Added** a new endpoint to retrieve the history of stablecoin issuance and redemption operations.
**Category**: Stablecoins
**Endpoint Added**:
* `GET /stablecoins/history`: Returns a historical list of your stablecoin issuance and redemption operations.
**Impact**: You can now programmatically access your stablecoin conversion history for tracking and reporting purposes.
## Added Binance as a Price Source for Collateral Management
**Added** support for `BINANCE` as a price source in Collateral Management.
**Category**: Collateral Management
**Endpoints Changed**:
* `GET /collateral_management/price_sources`: Now returns `BINANCE` as an available source and accepts it as a filter in the `exchange` query parameter.
* `POST /collateral_management/packages`: The `priceSource` field now accepts `BINANCE`.
* `PATCH /collateral_management/packages/{packageId}`: The `priceSource` field now accepts `BINANCE`.
* `POST /collateral_management/exposures`: The `priceSource` field now accepts `BINANCE`.
**Impact**: This allows for more flexible pricing options when creating and managing collateral packages and exposures.
**Example**:
```json theme={null}
"collateralAssetsConfig": [
{
"asset": {
"assetType": "BTC",
"type": "ANCHORAGECUSTODY"
},
"priceSource": "BINANCE",
"weight": "1.0",
"liquidationPriority": 1
}
]
```
## Added Accelerated Margin Call for Collateral Management
**Added** A new `acceleratedMarginCall` configuration level for collateral packages, letting you set an additional margin call threshold with its own LTV, cure period, and action.
**Category**: Collateral Management
**Endpoints Changed**:
* `POST /collateral_management/packages`: Accepts a new `acceleratedMarginCall` object in the request body.
* `PATCH /collateral_management/packages/{packageId}`: Accepts a new `acceleratedMarginCall` object in the request body.
* `GET /collateral_management/packages`: The response now includes the `acceleratedMarginCall` object.
**Impact**: You can now define and monitor an additional, accelerated margin call level for your collateral packages, providing more granular risk management.
## Removed TRUSTED\_DESTINATION Resource Type from Transfers and Wallets
**Removed** The `TRUSTED_DESTINATION` enum value from the `destination.type` field for transfer and withdrawal requests, and from the `type` field in several Wallet and Transfer responses.
**Category**: Transfers, Transactions, and Wallets
**Endpoints Changed**:
* `POST /transactions/withdrawal`: `destination.type` no longer accepts `TRUSTED_DESTINATION`; the `assetParametersATOM` field is now deprecated in favor of `assetParametersCosmos`.
* `POST /transfers`: `destination.type` no longer accepts `TRUSTED_DESTINATION`; the `assetParametersATOM` field is now deprecated in favor of `assetParametersCosmos`.
* `GET /transfers`: The `type` field in responses no longer returns `TRUSTED_DESTINATION`.
* `GET /transfers/{transferId}`: The `type` field in responses no longer returns `TRUSTED_DESTINATION`.
* `GET /vaults/{vaultId}/wallets`: The `type` field in responses no longer returns `TRUSTED_DESTINATION`.
* `POST /vaults/{vaultId}/wallets`: The `type` field in responses no longer returns `TRUSTED_DESTINATION`.
* `GET /wallets`: The `type` field in responses no longer returns `TRUSTED_DESTINATION`.
* `GET /wallets/{walletId}`: The `type` field in responses no longer returns `TRUSTED_DESTINATION`.
**Impact**: This is a breaking change. Requests that specify `destination.type` as `TRUSTED_DESTINATION` will now fail. To send funds to a trusted destination, use `destination.type: 'ADDRESS'` with the specific blockchain address, and update any logic that parses the `type` field in Wallet and Transfer responses. Users are encouraged to migrate from the deprecated `assetParametersATOM` to `assetParametersCosmos`.
## Improved Order Filtering Parameter Description
**Improved** the description for the `orderTypes` query parameter to enhance clarity.
**Category**: Trading
**Endpoint Changed**:
* `GET /trading/orders`: The description for the `orderTypes` parameter was updated.
**Impact**: This is a non-breaking documentation change. No integration updates are required.
## Improved Statement Filtering and Response Structure
**Improved** the Statements endpoints with updated filtering parameters and a restructured response body.
**Category**: Statements
**Endpoints Changed**:
* `GET /statements`: Removed the `statementIds`, `statementTypes`, `accountIds`, `affiliateIds`, `vaultGroupIds`, and `subaccountIds` filter parameters, and added `ids`, `typeIds`, and `customerIds`. The response no longer includes `accountId`, `affiliateId`, `subaccountId`, `vaultGroupId`, or the required `type` field, and now includes `customerId` and the new required `typeId` field (`type` is now optional).
* `GET /statements/{statementId}`: The response no longer includes `accountId`, `affiliateId`, `subaccountId`, `vaultGroupId`, or the required `type` field, and now includes `customerId` and the new required `typeId` field (`type` is now optional).
**Impact**: This is a breaking change. Integrations using the `/statements` endpoints must be updated to use the new query parameters and handle the modified response structure.
## Improved Order Type Support with MANUAL
**Improved** Added support for a new `MANUAL` order type.
**Category**: Trading
**Endpoints Changed**:
* `GET /trading/orders`: The `orderType` field in the response can now include `MANUAL`.
* `GET /trading/orders/{orderId}`: The `orderType` field in the response can now include `MANUAL`.
**Impact**: Clients should update their integrations to handle this new enum value when listing or retrieving orders.
## Improved Fiat Trusted Destination Response Structure
**Improved** The structure of the `fiat` object in the trusted destinations response has been refactored for clarity, with beneficiary and financial institution details now grouped into nested `beneficiary` and `beneficiaryBank` objects, plus new `intermediaryBank` and `usage` fields.
**Category**: Trusted Destinations
**Endpoint Changed**:
* `GET /trusted_destinations`: The `fiat` object's flat beneficiary and institution properties are now nested under `beneficiary` and `beneficiaryBank`, and the object gains `intermediaryBank` and `usage` fields.
**Impact**: This is a breaking change. Integrations that parsed the flat properties within the `fiat` object must be updated to handle the new nested structure. The new `usage` field indicates whether the recipient account is owned by your organization or a third party.
**Example**:
*Before:*
```json theme={null}
{
"fiat": {
"beneficiaryName": "Satoshi Nakamoto",
"beneficiaryAccount": "*****1234",
"institutionName": "The Bank of New York Mellon",
"institutionId": "IRVTUS3N",
//... other flat properties
}
}
```
*After:*
```json theme={null}
{
"fiat": {
"beneficiary": {
"name": "Satoshi Nakamoto",
"account": "*****1234",
//... other beneficiary properties
},
"beneficiaryBank": {
"name": "The Bank of New York Mellon",
"id": "IRVTUS3N",
//... other bank properties
},
"intermediaryBank": {},
"usage": "MY_ORGANIZATION"
}
}
```
## Added Fiat Support for Trusted Destinations
**Added** support for fiat (bank account) trusted destinations.
**Category**: Trusted Destinations
**Endpoint Changed**:
* `GET /trusted_destinations`: The response now includes details for fiat-based trusted destinations.
**Impact**: When listing trusted destinations, a fiat destination now has a `type` of `fiat` and contains a new `fiat` object with detailed bank account information.
**Example**:
```json theme={null}
{
"data": [
{
"id": "td_fiat_12345",
"name": "Corporate Bank Account",
"description": "Primary USD account",
"type": "fiat",
"owner": {
"id": "customer_abc",
"type": "CUSTOMER"
},
"fiat": {
"beneficiaryName": "Example Corp",
"beneficiaryAccount": "987654321",
"beneficiaryType": "BUSINESS",
"institutionName": "Example Bank",
"institutionId": "121000358",
"institutionCode": "ABA",
"memo": "For operating expenses"
},
"crypto": null
}
]
}
```
## Improved Order Allocation Details with Filled Quantity
**Improved** The `allocation` object in trading order responses now includes the `cumQty` field, which specifies the filled quantity for each subaccount allocation.
**Category**: Trading
**Endpoints Changed**:
* `POST /trading/order`: The `allocation` object in the response now includes the required `cumQty` field.
* `GET /trading/orders`: The `allocation` object in the response now includes the required `cumQty` field.
* `GET /trading/orders/{orderId}`: The `allocation` object in the response now includes the required `cumQty` field.
* `POST /trading/async-order`: The `allocation` object in the response now includes the required `cumQty` field.
* `POST /trading/async-order/cancel`: The `allocation` object in the response now includes the required `cumQty` field.
**Impact**: This is a non-breaking change that provides more granular data on order fills at the subaccount level.
**Example**:
```json theme={null}
"allocation": [
{
"subaccountId": "905272f0-52f9-404e-b6cd-ad879e671790",
"quantity": "10000",
"cumQty": "10000",
"counterQtyAllIn": "10000",
"counterQtyAllInToSettle": "10000",
"fee": "10000"
}
]
```
## Improved Collateral Management Price Sources Endpoint
**Improved** Added a new `501 Not Implemented` response and clarified the `exchange` query parameter description.
**Category**: Collateral Management
**Endpoint Changed**:
* `GET /collateral_management/price_sources`: Now returns a `501 Not Implemented` error if the price sources feature is disabled; the `exchange` parameter description was simplified.
**Impact**: API consumers will now receive a `501 Not Implemented` error if the price sources feature is disabled.
## Improved Clarity for Tax Reporting Deposit Transaction Endpoints
**Improved** descriptions for the Tax Reporting endpoints to clarify that cost basis management applies specifically to deposit transactions.
**Category**: Tax Reporting
**Endpoints Changed**:
* `PATCH /tax/accounts/{accountId}/transactions/{transactionId}`: The endpoint and `hasCostBasis` parameter descriptions were improved for accuracy.
* `GET /tax/accounts/{accountId}/transactions`: The endpoint and `hasCostBasis` parameter descriptions were improved for accuracy.
**Impact**: This is a documentation-only change to improve clarity. The functionality of the endpoints remains unchanged.
## Improved Async Order Responses with Counter Currency Details
**Improved** Added `counterCurrency`, `counterQty`, and `counterQtyAllIn` fields to the responses for placing and canceling async orders.
**Category**: Trading
**Endpoints Changed**:
* `POST /trading/async-order`: The response now includes `counterCurrency`, `counterQty`, and `counterQtyAllIn`.
* `POST /trading/async-order/cancel`: The response now includes `counterCurrency`, `counterQty`, and `counterQtyAllIn`.
**Impact**: The responses for placing and canceling an async order now include the counter currency, the filled quantity of the counter currency, and the filled quantity including all fees.
**Example**:
```json theme={null}
{
"data": {
"clOrderId": "6fb5fc79-0bb4-446d-82dd-d4687fb56a02",
"orderId": "a94c8d75-6c9d-4903-95f3-5b0893e76cb7",
// ... existing fields
"counterCurrency": "BTC",
"counterQty": "0.4760680586896702",
"counterQtyAllIn": "0.4760544606302961",
"transactTime": "2023-03-12T22:22:09.925050Z"
}
}
```
## Added Collateral Management Price Sources Endpoint
**Added** a new endpoint to get available price sources and their supported assets.
**Category**: Collateral Management
**Endpoint Added**:
* `GET /collateral_management/price_sources`: Returns supported price sources and the specific assets available for each source.
**Impact**: This lets clients programmatically retrieve supported price sources, which can be used to validate configurations for collateral packages.
## Improved Price Strategy Options for Collateral Management
**Improved** The `priceStrategy` options for creating and managing collateral packages and exposures now include `MID` and `LAST`; `VWAP` has been removed.
**Category**: Collateral Management
**Endpoints Changed**:
* `POST /collateral_management/packages`: The `priceStrategy` field now accepts `MID` and `LAST`; `VWAP` is no longer supported.
* `PATCH /collateral_management/packages/{packageId}`: The `priceStrategy` field now accepts `MID` and `LAST`; `VWAP` is no longer supported.
* `POST /collateral_management/exposures`: The `priceStrategy` field now accepts `MID` and `LAST`; `VWAP` is no longer supported.
**Impact**: This is a breaking change. Integrations using the `priceStrategy` field must switch from `VWAP` to `MID` or `LAST`.
## Added Fiat Parameters for Trusted Destination Transfers and Withdrawals
**Added** A new `assetParametersFiatTrustedDestination` object to the request body for fiat transfers and withdrawals to Trusted Destinations.
**Category**: Transactions, Transfers
**Endpoints Changed**:
* `POST /transactions/withdrawal`: Accepts a new optional `assetParametersFiatTrustedDestination` object with `memo` and `purpose` fields.
* `POST /transfers`: Accepts a new optional `assetParametersFiatTrustedDestination` object with `memo` and `purpose` fields.
**Impact**: This lets you provide additional context when sending fiat assets to a Trusted Destination, which is useful for record-keeping and compliance.
**Example**:
```json theme={null}
{
"assetType": "USD",
"amount": "5000.00",
"source": {
"id": "1c920f4241b78a1d483a29f3c24b6c4c",
"type": "WALLET"
},
"destination": {
"id": "td_123abc...",
"type": "TRUSTED_DESTINATION"
},
"assetParametersFiatTrustedDestination": {
"memo": "Q1 Payout",
"purpose": "INVESTMENT"
},
"idempotentId": "unique-withdrawal-id-123"
}
```
## Improved Offchain Vesting Schedule Response with Asset Type
**Improved** the response for listing offchain vesting schedules to include the asset type.
**Category**: Vesting
**Endpoint Changed**:
* `GET /offchainvesting/schedules`: Each schedule object in the `data` array now includes the `assetType` field, specifying the asset abbreviation (for example, BTC or ETH).
**Impact**: This is a non-breaking, additive change that makes it easier to identify the asset associated with each vesting schedule directly from the list endpoint.
## Improved Transfers and Withdrawals with Trusted Destinations
**Improved** You can now use pre-configured Trusted Destinations when creating transfers and withdrawals, sending funds to a `TRUSTED_DESTINATION` ID instead of a full address.
**Category**: Transfers & Withdrawals
**Endpoints Changed**:
* `POST /transfers`: The `destination.type` field now accepts `TRUSTED_DESTINATION`.
* `POST /transactions/withdrawal`: The `destination.type` field now accepts `TRUSTED_DESTINATION`.
* `GET /transfers`: The response can now reflect `TRUSTED_DESTINATION` as a destination type.
* `GET /transfers/{transferId}`: The response can now reflect `TRUSTED_DESTINATION` as a destination type.
**Impact**: When sending to a `TRUSTED_DESTINATION`, you no longer need to include asset-specific parameters like `assetParametersXRP` or `assetParametersXLM` — the destination tag or memo is inherited automatically from the trusted destination's configuration.
**Example**:
```json theme={null}
// POST /transactions/withdrawal
{
"assetType": "XRP",
"amount": "100.0",
"source": {
"id": "your_wallet_id",
"type": "WALLET"
},
"destination": {
"id": "your_trusted_destination_id",
"type": "TRUSTED_DESTINATION"
},
"idempotentId": "unique-id-for-withdrawal-123"
}
```
## Improved Market Data Endpoint with Amount-Based Depth
**Improved** The market data endpoint now supports returning market depth by notional value, such as USD, in addition to asset size.
**Category**: Trading
**Endpoint Changed**:
* `GET /trading/marketdata`: A new `amount` field has been added to the `bids` and `offers` objects, returned when using the `amountBuckets` query parameter; the existing `size` field is returned when using `sizeBuckets`.
**Impact**: This is a non-breaking change that lets you request market depth in notional terms instead of, or alongside, asset size.
**Example**:
```json theme={null}
// Request using amountBuckets
GET /trading/marketdata?symbol=BTC-USD&amountBuckets=10000,50000
// Sample Response Snippet
"bids": [
{
"price": "65000.00",
"amount": "10000.00" // New field: value in USD
},
{
"price": "64950.00",
"amount": "50000.00" // New field: value in USD
}
]
```
## Added Endpoint to Propose Trusted Counterparties
**Added** A new endpoint to propose a new trusted counterparty.
**Category**: Atlas Settlement Network
**Endpoint Added**:
* `POST /atlas/directory/counterparties`: Proposes a new trusted counterparty.
**Impact**: You can now programmatically propose new trusted counterparties, streamlining the process of adding new settlement partners.
## Improved Market Data Parameter Descriptions
**Improved** descriptions for the `sizeBuckets` and `amountBuckets` query parameters to clarify their usage and impact on the response.
**Category**: Trading
**Endpoint Changed**:
* `GET /trading/marketdata`: `sizeBuckets` is clarified as a comma-separated list; `amountBuckets` is clarified as a comma-separated list of USD values, with a note that using it affects how `size` is represented in the response.
**Impact**: This is a non-breaking documentation change that provides better guidance for querying market depth.
## Improved Cost Basis Reporting with Tax Lots
**Improved** the Tax Reporting endpoints to support lot-level cost basis management for more granular and accurate tax data.
**Category**: Tax Reporting
**Endpoints Changed**:
* `PATCH /tax/accounts/{accountId}/transactions/{transactionId}`: The request body now requires a `lots` array (each with `lotId`, `quantity`, and `costBasis`) in place of the previous `data`, `acquisitionDatetime`, and `assetType` fields.
* `GET /tax/accounts/{accountId}/transactions`: The response now includes a required top-level `assetType` field per transaction, and an `acquisitionDatetime` field on each lot in the `receivedAssets` array.
**Impact**: This moves cost basis reporting from a per-transaction model to a per-lot model, letting you specify and retrieve cost basis information for individual lots within a single transaction.
## Added Market Data Endpoint
**Added** a new endpoint to retrieve a snapshot of market data.
**Category**: Trading
**Endpoint Added**:
* `GET /trading/marketdata`: Returns a snapshot of current market data.
**Impact**: You can now programmatically access market data for pricing, analysis, and other trading-related activities. See the [Market Data Guide](https://developers.anchorage.com/docs/websocket-api-market-data) for more information.
## Improved Transaction Types and Settlement Parameter Documentation
**Improved** Added the `FIAT_INTEREST` transaction type and clarified the `applyPostLock` parameter description.
**Category**: Transactions, Atlas Settlement Network
**Endpoints Changed**:
* `GET /transactions`: The `transactionType` field in the response can now include `FIAT_INTEREST`, representing fiat interest payments.
* `GET /transactions/{transactionId}`: The `transactionType` field in the response can now include `FIAT_INTEREST`, representing fiat interest payments.
* `POST /atlas/settlements`: The description for the `applyPostLock` parameter now clarifies it applies only to clients using Atlas settlements integrated with Anchorage Vesting.
**Impact**: Clients should update their systems to handle the new `FIAT_INTEREST` transaction type. The `applyPostLock` documentation change is non-breaking and only clarifies existing behavior.
## Deprecated `totalDistribution` Field in Tax Tagging
**Deprecated** the `totalDistribution` field for tagging tax transactions.
**Category**: Tax
**Endpoint Changed**:
* `POST /tax/transaction/{transactionId}/tag`: The `totalDistribution` field in the request body is now deprecated and ignored if provided.
**Impact**: Any value passed in `totalDistribution` is disregarded — total distribution status is now calculated automatically from account balances. Remove this field from your requests, since it no longer has any effect.
## Added Post-Settlement Locking for Atlas Settlements
**Added** a new `applyPostLock` parameter to automatically create post-settlement holds on funds received through the Atlas Settlement Network.
**Category**: Atlas Settlement Network
**Endpoint Changed**:
* `POST /atlas/settlements`: Accepts a new optional boolean `applyPostLock` parameter; when `true`, indefinite holds are placed on the acceptor's destination wallets after a successful settlement.
**Impact**: This enables the automatic creation of post-settlement vesting schedules on received funds, streamlining workflows that require funds to be locked after settlement.
## Added Vesting Schedules Endpoint and Tax Transaction Cost Basis Filter
**Added** a new endpoint for listing offchain vesting schedules and a new filter for tax transactions.
**Category**: Vesting, Tax Reporting
**Endpoints Changed**:
* `GET /offchainvesting/schedules`: New endpoint that lists all offchain vesting schedules for your organization.
* `GET /tax/accounts/{accountId}/transactions`: Accepts a new `hasCostBasis` query parameter to filter transactions that do or don't have a cost basis.
**Impact**: This provides programmatic access to vesting schedules and lets you filter tax transactions by whether they have a cost basis, improving transparency and reporting.
## Improved Transaction Types with Priority Fee Reward
**Improved** The `transactionType` field in transaction-related endpoints now includes `PRIORITY_FEE_REWARD` to represent priority fee rewards.
**Category**: Transactions
**Endpoints Changed**:
* `GET /transactions`: The `transactionType` field in the response can now include `PRIORITY_FEE_REWARD`.
* `GET /transactions/{transactionId}`: The `transactionType` field in the response can now include `PRIORITY_FEE_REWARD`.
**Impact**: This new type identifies priority fee rewards, such as those from Jito priority fee distributions on Solana.
## Improved Clarity for Trusted Destination Asset Type
**Improved** The description for the `assetType` field has been updated to provide better clarity when creating a trusted destination.
**Category**: Trusted Destinations
**Endpoint Changed**:
* `POST /trusted_destinations`: The description for `assetType` in the `trustedDestinations` array now clarifies what an asset type is and points to `GET /asset-types` for a list of supported types.
**Impact**: This is a non-breaking documentation change. The endpoint's functionality remains the same.
## Improved Security with Signature Requirements for Collateral Management
**Improved** security by requiring `Api-Signature` and `Api-Timestamp` headers for write operations on Collateral Management endpoints.
**Category**: Collateral Management
**Endpoints Changed**:
* `PATCH /collateral_management/operations/{operationId}`: Now requires `Api-Signature` and `Api-Timestamp` headers.
* `PATCH /collateral_management/packages/{packageId}`: Now requires `Api-Signature` and `Api-Timestamp` headers.
* `POST /collateral_management/exposures`: Now requires `Api-Signature` and `Api-Timestamp` headers.
* `POST /collateral_management/operations`: Now requires `Api-Signature` and `Api-Timestamp` headers.
* `POST /collateral_management/packages`: Now requires `Api-Signature` and `Api-Timestamp` headers.
**Impact**: This is a breaking change. Requests to these endpoints will now fail if they don't include valid signature and timestamp headers. See the Request Signatures section of the documentation for instructions on generating a valid signature.
## Improved Wallet Responses with Unvested and Unstakeable Balances
**Improved** Wallet-related endpoints now include more detailed balance information for offchain vesting.
**Category**: Wallets
**Endpoints Changed**:
* `GET /vaults/{vaultId}/wallets`: The `assets` object now includes `unvestedBalance` and `unvestedUnstakeableBalance` fields.
* `POST /vaults/{vaultId}/wallets`: The `assets` object now includes `unvestedBalance` and `unvestedUnstakeableBalance` fields.
* `GET /wallets`: The `assets` object now includes `unvestedBalance` and `unvestedUnstakeableBalance` fields.
* `GET /wallets/{walletId}`: The `assets` object now includes `unvestedBalance` and `unvestedUnstakeableBalance` fields.
**Impact**: This is a non-breaking change. Responses now contain additional balance details for assets in offchain vesting contracts, where applicable.
## Improved Vesting Balance Retrieval for Multiple Allocations
**Improved** vesting balance retrieval by adding a new endpoint to fetch balances for multiple allocations in a single request.
**Category**: Vesting
**Endpoint Added**:
* `POST /vesting/balances`: Retrieves vesting balances for multiple allocations in a single request.
**Impact**: This allows for more efficient retrieval of balance data by fetching information for multiple allocations at once, reducing the number of required API calls.
## Improved Security with Request Signing for Atlas Settlement Endpoints
**Improved** security by adding request signing to key Atlas Settlement Network endpoints, which now require `Api-Signature` and `Api-Timestamp` headers.
**Category**: Atlas Settlement Network
**Endpoints Changed**:
* `POST /atlas/settlements`: Now requires `Api-Signature` and `Api-Timestamp` headers.
* `POST /atlas/settlements/{settlementId}/accept`: Now requires `Api-Signature` and `Api-Timestamp` headers.
* `POST /atlas/settlements/{settlementId}/authorize`: Now requires `Api-Signature` and `Api-Timestamp` headers.
* `POST /atlas/settlements/{settlementId}/reject`: Now requires `Api-Signature` and `Api-Timestamp` headers.
**Impact**: This is a breaking change. Requests made to the listed endpoints will now fail if they don't include the required signature headers. See the Request Signatures section of the documentation for instructions on generating the required signatures.
## Improved Stablecoin Conversion Documentation
**Improved** the description for the `sourceAssetType` field in the stablecoin conversion request body for clarity.
**Category**: Stablecoins
**Endpoint Changed**:
* `POST /stablecoins/conversion`: The `sourceAssetType` description now clarifies that it must be `USD` for an issuance, and the asset being redeemed for a redemption.
**Impact**: This is a non-breaking documentation change.
## Improved Staking Request Descriptions
**Improved** The descriptions for the `parameters` object and the `stakingProviderAddress` field for Solana staking requests have been updated for clarity.
**Category**: Transactions
**Endpoint Changed**:
* `POST /transactions/stake`: The description for the `parameters` object was updated, and within `SOLStakingParameters`, `stakingProviderAddress` now describes "the validator's vote account address" instead of "the validator's staking address".
**Impact**: This is a non-breaking documentation change to provide better clarity for clients creating Solana (SOL) staking requests.
## Added Endpoint for Consolidating Stakes
**Added** a new endpoint to create a consolidate stake request.
**Category**: Transactions
**Endpoint Added**:
* `POST /transactions/consolidate-stake`: Initiates a request to consolidate staking positions.
**Impact**: This feature enhances staking management by allowing users to consolidate stakes directly through the API. See the [staking guide](https://developers.anchorage.com/docs/ethereum-pectra-staking-api#consolidate-pectra-to-pectra-validator) for instructions on use.
## Improved Backward Compatibility by Re-introducing the VAULT Resource Type
**Improved** backward compatibility by re-introducing the `VAULT` enum value for source and destination resources; it's accepted but deprecated in favor of `WALLET`.
**Category**: Transfers, Wallets, and Transactions
**Endpoints Changed**:
* `POST /transactions/withdrawal`: Accepts `VAULT` again as a resource type, though deprecated in favor of `WALLET`.
* `POST /transfers`: Accepts `VAULT` again as a resource type, though deprecated in favor of `WALLET`.
* `GET /transfers`: Accepts `VAULT` again as a resource type, though deprecated in favor of `WALLET`.
* `GET /transfers/{transferId}`: Accepts `VAULT` again as a resource type, though deprecated in favor of `WALLET`.
* `GET /vaults/{vaultId}/wallets`: Accepts `VAULT` again as a resource type, though deprecated in favor of `WALLET`.
* `POST /vaults/{vaultId}/wallets`: Accepts `VAULT` again as a resource type, though deprecated in favor of `WALLET`.
* `GET /wallets`: Accepts `VAULT` again as a resource type, though deprecated in favor of `WALLET`.
* `GET /wallets/{walletId}`: Accepts `VAULT` again as a resource type, though deprecated in favor of `WALLET`.
**Impact**: This restores backward compatibility for integrations still using the `VAULT` resource type. We strongly recommend updating existing code to use `WALLET` instead, since support for `VAULT` will be removed in a future release.
## Fixed AML Questionnaire Requirement by Organization Type
**Fixed** The `trustedDestinationAmlQuestionnaire` field is now conditionally required based on the organization type.
**Category**: Trusted Destinations
**Endpoint Changed**:
* `POST /trusted_destinations`: The `trustedDestinationAmlQuestionnaire` field is now required for Anchorage Digital organizations and must be omitted for Porto organizations.
**Impact**: Requests to create a trusted destination will now fail if `trustedDestinationAmlQuestionnaire` is included for a Porto organization or omitted for an Anchorage Digital organization.
## Added Endpoints for Tax Account Management
**Added** new endpoints to the Tax API for managing tax accounts and their associated transactions.
**Category**: Tax
**Endpoints Added**:
* `GET /tax/accounts`: Lists tax accounts.
* `GET /tax/accounts/{accountId}/transactions`: Retrieves transactions for a specific tax account.
* `PATCH /tax/accounts/{accountId}/transactions/{transactionId}`: Updates the cost basis of a transaction for tax reporting.
**Impact**: These new endpoints let you list tax accounts, retrieve transactions for a specific account, and update the cost basis of a transaction for tax reporting purposes.
## Removed TRUSTED\_DESTINATION as a Resource Type
**Removed** The `TRUSTED_DESTINATION` value as a valid enum for the resource `type` field.
**Category**: Transfers, Withdrawals, Wallets
**Endpoints Changed**:
* `POST /transactions/withdrawal`: The `destination.type` field no longer accepts `TRUSTED_DESTINATION`.
* `POST /transfers`: The `destination.type` field no longer accepts `TRUSTED_DESTINATION`.
* `GET /transfers`: The `type` field in responses no longer returns `TRUSTED_DESTINATION`.
* `GET /transfers/{transferId}`: The `type` field in responses no longer returns `TRUSTED_DESTINATION`.
* `GET /vaults/{vaultId}/wallets`: The `type` field in responses no longer returns `TRUSTED_DESTINATION`.
* `POST /vaults/{vaultId}/wallets`: The `type` field in responses no longer returns `TRUSTED_DESTINATION`.
* `GET /wallets`: The `type` field in responses no longer returns `TRUSTED_DESTINATION`.
* `GET /wallets/{walletId}`: The `type` field in responses no longer returns `TRUSTED_DESTINATION`.
**Impact**: This is a breaking change. API calls using `destination.type: TRUSTED_DESTINATION` will now fail. Specify the underlying `ADDRESS` or `WALLET` directly when creating transfers or withdrawals.
## Improved Tax Transaction Tagging with IRS Combination Codes
**Improved** The `distributionCode` field for tagging tax transactions now supports IRS combination codes.
**Category**: Tax
**Endpoint Changed**:
* `POST /tax/transaction/{transactionId}/tag`: The `distributionCode` field now accepts combination codes (for example, `1B`, `4G`, `7B`) as valid enum values.
**Impact**: This allows for more accurate tax reporting when a distribution has multiple applicable IRS classifications, such as using `4G` for a death-related direct rollover.
## Improved Collateral Management Operations with Liquidation Details
**Improved** The response for Collateral Management Operations now includes liquidation details and an update timestamp.
**Category**: Collateral Management
**Endpoints Changed**:
* `PATCH /collateral_management/operations/{operationId}`: The `CMOperation` model now includes `updatedAt`, `liquidationCollateralPackageId`, `liquidationProceedAsset`, and `liquidationProceedQuantity`.
* `GET /collateral_management/operations`: The `CMOperation` model now includes `updatedAt`, `liquidationCollateralPackageId`, `liquidationProceedAsset`, and `liquidationProceedQuantity`.
**Impact**: This provides more comprehensive data on operations, particularly those involving liquidations.
## Improved API Key Info Response with WRITE\_TAX Permission
**Improved** Added the new `WRITE_TAX` permission type, which now appears in the response for the get API key info endpoint.
**Category**: API Key
**Endpoint Changed**:
* `GET /apikey`: The `permissions` array in the response now includes `WRITE_TAX` for API keys that have this permission.
**Impact**: This is a non-breaking change.
**Example**:
```json theme={null}
{
"data": {
"id": "b5a58566763e77e2d87a53463013981be7c0b048c1c0dd39ba44e77c99bc1351",
"permissions": [
{
"permission": "READ",
"vaultIds": [
"1c920f4241b78a1d483a29f3c24b6c4c"
]
},
{
"permission": "WRITE_TAX"
}
]
}
}
```
## Added AML Questionnaire to Trusted Destination Creation
**Added** an optional `trustedDestinationAmlQuestionnaire` object to the request body for creating trusted destinations, so Anti-Money Laundering information can be submitted upfront.
**Category**: Trusted Destinations
**Endpoint Changed**:
* `POST /trusted_destinations`: Accepts an optional `trustedDestinationAmlQuestionnaire` object within each item of the `trustedDestinations` array.
**Impact**: This is a non-breaking change. Providing AML information when creating a trusted destination can streamline the approval process for future withdrawals to that address.
**Example**:
```json theme={null}
{
"idempotentId": "1ca86e65-4340-4876-85f4-8334852b9c43",
"owner": {
"type": "CUSTOMER",
"id": "your-customer-id"
},
"trustedDestinations": [
{
"assetType": "BTC",
"address": "2N19AcihQ1a4MxQW658UFHTioUNnMkiHPkw",
"name": "My Exchange Wallet",
"description": "BTC wallet at Example Exchange",
"trustedDestinationAmlQuestionnaire": {
"destinationType": "FINANCIAL_INSTITUTION",
"institutionName": "Example Exchange",
"institutionCountry": "US",
"recipientType": "DESTINATION_INSTITUTION"
}
}
]
}
```
## Improved Deposit Address Security with V2 Signatures
**Improved** security by introducing a V2 signature scheme for deposit addresses.
**Category**: Addresses, Wallets
**Endpoints Changed**:
* `GET /vaults/{vaultId}/addresses`: Signed address responses can now include `signatureVersion` and `certChain` fields.
* `POST /wallets/{walletId}/addresses`: Signed address responses can now include `signatureVersion` and `certChain` fields.
* `GET /vaults/{vaultId}/wallets`: Signed address responses can now include `signatureVersion` and `certChain` fields.
* `POST /vaults/{vaultId}/wallets`: Signed address responses can now include `signatureVersion` and `certChain` fields.
* `GET /wallets`: Signed address responses can now include `signatureVersion` and `certChain` fields.
* `GET /wallets/{walletId}`: Signed address responses can now include `signatureVersion` and `certChain` fields.
**Impact**: This is a backward-compatible change that gives clients a more robust, certificate-based way to verify deposit address authenticity. When `signatureVersion` is `V2`, the `certChain` field contains an x509 certificate chain for verification against a trusted Anchorage Digital Root CA; if `certChain` is absent, use the existing V1 signature verification method. See the [Address Verification guide](https://developers.anchorage.com/docs/address-verification) for instructions.
## Added MINT Transaction Type
**Added** `MINT` as a new transaction type to represent assets minted or created on the blockchain.
**Category**: Transactions
**Endpoints Changed**:
* `GET /transactions`: The `types` query parameter now accepts `MINT` to filter transactions, and the `transactionType` field in the response can now return `MINT`.
* `GET /transactions/{transactionId}`: The `transactionType` field in the response can now return `MINT`.
**Impact**: You can now filter for and identify `MINT` transactions across both the list and single-transaction endpoints.
## Improved Error Handling for Collateral Package Updates
**Improved** error handling by adding a new `422 Unprocessable Entity` error response to the update collateral package endpoint.
**Category**: Collateral Management
**Endpoint Changed**:
* `PATCH /collateral_management/packages/{packageId}`: Now returns `422 Unprocessable Entity` for requests that are syntactically correct but semantically invalid.
**Impact**: This lets clients differentiate between a bad request (`400`), a resource not found (`404`), and an unprocessable entity (`422`).
## Improved Pricing Options for Collateral Management
**Improved** Added new options for price strategy and price source to provide more flexibility in Collateral Management configurations.
**Category**: Collateral Management
**Endpoints Changed**:
* `POST /collateral_management/packages`: The `priceStrategy` field now accepts `VWAP`, and the `priceSource` field now accepts `KAMINO`.
* `PATCH /collateral_management/packages/{packageId}`: The `priceStrategy` field now accepts `VWAP`, and the `priceSource` field now accepts `KAMINO`.
* `POST /collateral_management/exposures`: The `priceStrategy` field now accepts `VWAP`, and the `priceSource` field now accepts `KAMINO`.
**Impact**: You can now specify `VWAP` (Volume-Weighted Average Price) as a pricing strategy and `KAMINO` as a price source when creating or updating collateral packages and exposures.
## Added BURN Transaction Type
**Added** a new `BURN` transaction type to represent assets that are burned or destroyed on the blockchain.
**Category**: Transactions
**Endpoints Changed**:
* `GET /transactions`: The `types` query parameter now accepts `BURN` to filter transactions, and the `transactionType` field in the response can now return `BURN`.
* `GET /transactions/{transactionId}`: The `transactionType` field in the response can now return `BURN`.
**Impact**: This helps with clearer categorization of on-chain asset destruction events.
## Removed priceSourceProvider from Collateral Management Endpoints
**Removed** the `priceSourceProvider` field from the request bodies of several Collateral Management endpoints.
**Category**: Collateral Management
**Endpoints Changed**:
* `POST /collateral_management/packages`: The `priceSourceProvider` field is no longer available in `collateralAssetsConfig`.
* `PATCH /collateral_management/packages/{packageId}`: The `priceSourceProvider` field is no longer available in `collateralAssetsConfig`.
* `POST /collateral_management/exposures`: The `priceSourceProvider` field is no longer available in `assetTrackingConfig`.
**Impact**: API requests that include the `priceSourceProvider` field will now result in an error. Update your integrations to remove this field to ensure successful requests.
## Improved Collateral Management Operations with GAS\_FEE Action
**Improved** the `CMOperation` model to include a new `GAS_FEE` action type.
**Category**: Collateral Management
**Endpoints Changed**:
* `PATCH /collateral_management/operations/{operationId}`: The `action` field in the response can now include `GAS_FEE`.
* `GET /collateral_management/operations`: The `action` field in the response can now include `GAS_FEE`.
**Impact**: This provides more granular detail on operation types.
## Improved Fiat Deposit Instructions with Memo Field
**Improved** A `memoField` has been added to the `depositInstruction` object returned for fiat wallets.
**Category**: Wallets
**Endpoints Changed**:
* `GET /vaults/{vaultId}/wallets`: The `depositInstruction` object for fiat wallets now includes `memoField`.
* `POST /vaults/{vaultId}/wallets`: The `depositInstruction` object for fiat wallets now includes `memoField`.
* `GET /wallets`: The `depositInstruction` object for fiat wallets now includes `memoField`.
* `GET /wallets/{walletId}`: The `depositInstruction` object for fiat wallets now includes `memoField`.
**Impact**: This is a non-breaking, additive change. Include this memo on wire deposits to ensure funds are attributed correctly to the wallet.
**Example**:
```json theme={null}
"depositInstruction": {
"memoField": "123456789",
"bankName": "Example Bank",
"bankRoutingNumber": "123456789",
"bankAddress": "123 Main Street, Anytown, USA 12345",
"bankSwiftCode": "12345678",
"beneficiaryName": "John Doe",
"beneficiaryAddress": "123 Main Street, Anytown, USA 12345",
"beneficiaryAccountNumber": "12345678"
}
```
## Improved Wallet Details with Fiat Deposit Instructions
**Improved** Wallet-related endpoints now include a `depositInstruction` object with banking details for fiat wallets, distinct from crypto wallet addresses.
**Category**: Wallets
**Endpoints Changed**:
* `GET /vaults/{vaultId}/wallets`: The response now conditionally includes the `depositInstruction` object for fiat wallets.
* `POST /vaults/{vaultId}/wallets`: The response now conditionally includes the `depositInstruction` object for fiat wallets.
* `GET /wallets`: The response now conditionally includes the `depositInstruction` object for fiat wallets.
* `GET /wallets/{walletId}`: The response now conditionally includes the `depositInstruction` object for fiat wallets.
**Impact**: The `depositAddress` object remains for crypto wallets. The description for the `assets` array has also been clarified to state that it may be empty.
**Example**:
```json theme={null}
"depositInstruction": {
"bankName": "Example Bank",
"bankAddress": "123 Finance St, New York, NY",
"bankRoutingNumber": "123456789",
"bankSwiftCode": "EXMPUS33",
"beneficiaryName": "Anchorage Digital Bank, N.A.",
"beneficiaryAddress": "456 Custody Ave, Sioux Falls, SD",
"beneficiaryAccountNumber": "987654321",
"memoField": "For further credit to [Your Org Name]"
}
```
## Improved Collateral Management Package Updates and API Refinements
**Improved** the Collateral Management API for more comprehensive control and clarity, including support for partial updates to a package's entire configuration.
**Category**: Collateral Management
**Endpoints Changed**:
* `PATCH /collateral_management/packages/{packageId}`: You can now update nearly all configuration details of a package, including `clientReferenceId`, `collateralAssetsConfig`, `ltvRoundingPrecision`, `priceStrategy`, and settings for `critical`, `marginCall`, `marginReturn`, and `autoDeleveraging` levels; omitted fields remain unchanged.
* `PATCH /collateral_management/operations/{operationId}`: The `type` field no longer accepts the `LIQUIDATION` enum value, and the `typeId` description was improved for clarity.
* `POST /collateral_management/operations`: The `type` field no longer accepts the `LIQUIDATION` enum value, and the `typeId` description was improved for clarity.
* `GET /collateral_management/exposures`: Field descriptions were updated for accuracy and clarity.
* `POST /collateral_management/packages`: Field descriptions were updated for accuracy and clarity.
* `GET /collateral_management/packages`: Field descriptions were updated for accuracy and clarity.
**Impact**: These changes provide significantly more flexibility for programmatically managing collateral packages and improve the overall clarity and usability of the Collateral Management API.
## Added Collateral Management Operation Actions
**Added** new `action` types for creating and updating Collateral Management operations.
**Category**: Collateral Management
**Endpoints Changed**:
* `POST /collateral_management/operations`: The `action` field now supports `CLOSE_RETURN`, `REHYPE_IN`, and `REHYPE_OUT`.
* `PATCH /collateral_management/operations/{operationId}`: The `action` field now supports `CLOSE_RETURN`, `REHYPE_IN`, and `REHYPE_OUT`.
**Impact**: You can now create and update operations to manage the closing of returns and rehypothecation for collateral packages.
## Added Fields for Tax Transaction Tagging
**Added** new conditional fields for tagging tax transactions to support more detailed reporting.
**Category**: Tax
**Endpoint Changed**:
* `POST /tax/transaction/{transactionId}/tag`: The request body now supports `distributionCode` (required when `tag` is `distribution`), `totalDistribution` (required when `tag` is `distribution`), and `postponedLateReason` (required when `tag` is `postponed` or `late-rollover`).
**Impact**: When tagging transactions with `distribution`, `postponed`, or `late-rollover`, you must now provide these additional details for more accurate tax reporting.
**Example**:
```json theme={null}
{
"accountId": "SubaccountID",
"tag": "distribution",
"taxYear": "2024",
"distributionCode": "1",
"totalDistribution": true
}
```
## Improved Collateral Management API Clarity and Field Support
**Improved** several Collateral Management endpoints for clarity and functionality, with updated field descriptions and examples throughout.
**Category**: Collateral Management
**Endpoints Changed**:
* `POST /collateral_management/packages`: Removed the `defaultGroupId` parameter from the request body.
* `GET /collateral_management/packages`: Removed `acceleratedMarginCall` from the response, and added `CURE_PERIOD_EXPIRED` and `DEFAULTED` to the `state` enum.
* `POST /collateral_management/exposures`: Descriptions improved for clarity.
* `GET /collateral_management/exposures`: Descriptions improved for clarity.
* `POST /collateral_management/operations`: Removed several unsupported enum values from the `action` field to reflect currently available actions.
* `GET /collateral_management/operations`: Descriptions improved for clarity.
* `PATCH /collateral_management/operations/{operationId}`: Removed several unsupported enum values from the `action` field to reflect currently available actions.
**Impact**: Descriptions were improved across all listed endpoints for parameters such as `clientReferenceId`, `pledgorId`, `curePeriod`, `ltv`, and `topUpType`, giving clearer guidance when configuring collateral packages, exposures, and operations.
## Improved Price Strategy Options with BID and ASK
**Improved** Added `BID` and `ASK` as valid options for the `priceStrategy` field when creating collateral packages and exposures.
**Category**: Collateral Management
**Endpoints Changed**:
* `POST /collateral_management/packages`: The `priceStrategy` field now accepts `BID` and `ASK`.
* `POST /collateral_management/exposures`: The `priceStrategy` field now accepts `BID` and `ASK`.
**Impact**: This provides more granular control over pricing strategy, letting you specify whether the bid or ask price should be used when creating new collateral packages and exposures.
## Improved Filtering for List Orders Endpoint
**Improved** order filtering capabilities by adding a new `orderTypes` parameter.
**Category**: Trading
**Endpoint Changed**:
* `GET /trading/orders`: Accepts a new optional `orderTypes` query parameter, an array of strings to filter by order type (`LIMIT`, `MARKET`, `STOP_LOSS`, `STOP_LIMIT`, `TAKE_PROFIT_LIMIT`, `TWAP`, `VWAP`, `PEGGED`, `POV`, `OTHER`).
**Impact**: This allows for more granular querying of orders, letting you retrieve only the specific order types you're interested in.
**Example**: `GET /v2/trading/orders?orderTypes=LIMIT,STOP_LIMIT`
## Improved Customer Onboarding with Single-Call Submission
**Improved** the customer onboarding workflow by adding an optional `submit` parameter.
**Category**: Onboarding
**Endpoint Changed**:
* `POST /onboarding/customers`: Accepts a new optional boolean `submit` parameter.
**Impact**: This is a non-breaking change. When `submit` is `true`, the application is created and submitted in a single call, eliminating the need for a separate submission request and reducing the number of required API calls.
## Improved Price Source Options with KRAKEN
**Improved** Added `KRAKEN` as a supported price source for collateral management.
**Category**: Collateral Management
**Endpoints Changed**:
* `POST /collateral_management/packages`: The `priceSource` field now accepts `KRAKEN`.
* `POST /collateral_management/exposures`: The `priceSource` field now accepts `KRAKEN`.
**Impact**: This provides more flexibility by letting you select Kraken as the data source for asset pricing when configuring collateral.
# Errors, rate limits, and pagination
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/errors-pagination
Understand Anchorage API status codes, rate limits, idempotent retries, and cursor pagination.
Standard HTTP status codes with a human-readable error message when requests fail.
Know your limits when accessing the Anchorage API to avoid 429 errors.
Required on certain endpoints to avoid duplicative operations.
Paginate through pages of API results.
## Status codes
| Code | Meaning |
| ----------------------- | -------------------------------------------------------------------------------------------------------------------- |
| `200 OK` | The request was successful. |
| `400 Bad Request` | The request was improperly formed, often due to invalid syntax, insufficient funds, or a missing required parameter. |
| `401 Unauthorized` | The request was missing a valid API key. |
| `403 Forbidden` | The API key does not have permission to perform the requested action. |
| `404 Not Found` | The requested resource does not exist. |
| `409 Conflict` | The requested action cannot proceed because the resource is not in the required state. |
| `429 Too Many Requests` | Too many requests were sent in a given amount of time. |
| `5xx` | Something went wrong on Anchorage Digital's side. |
### Common money movement errors
These are the failures developers hit most often when moving assets, and how to resolve each.
| Symptom | Likely cause | Resolution |
| :------------------------------------------------------------------------------------------ | :----------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `403` on an external transfer (`Cannot find role permission action for external transfers`) | The key's permission group doesn't have external transfers enabled, or a destination-scoped permission isn't connected to the destination. | Enable external transfers on the permission group. If the permission is scoped to specific destinations, connect the trusted destination to the group and endorse it. See [Permission groups and API keys](/knowledge-base/porto/developers/move-money/setup/permission-groups). |
| `403` on any movement | The key lacks the required permission for the source vault (for example `Transfer funds` or `Initiate withdrawals`). | Grant the permission to the key's group and re-endorse. |
| `400` insufficient funds | The amount plus the network fee exceeds the wallet's available balance. | Lower the amount, or on transfers set `deductFeeFromAmountIfSameType: true` to net the fee out of the amount. |
| `400` invalid or unsupported | A required field is missing, or the source wallet or destination doesn't support the asset. | Confirm the asset (`GET /v2/asset-types`) and that both source and destination support it. |
| `409` conflict on a withdrawal | A withdrawal is already in flight from the source wallet—withdrawals don't queue. | Wait for the in-flight withdrawal to broadcast or fail, then retry. |
| `429` too many requests | The org-wide rate limit was exceeded. | Back off and retry (see [Retries and backoff](#retries-and-backoff)). |
A request that returns `201` can still fail at execution—after quorum approval or at broadcast—if there are insufficient funds for the network fee or a blockchain-level failure occurs. Track terminal status via [Track movement status](/knowledge-base/porto/developers/move-money/operate/track-status).
## Rate limits
Keys provisioned by an organization share one common rate limit. API requests are
limited to `20 requests/second` per organization, allowing bursts of up to `100
requests` within a single second.
## Idempotency
Certain endpoints support idempotent requests so retries do not perform the same
operation twice. For example, if a transfer request does not respond because of a
network issue, retry with the same idempotent ID to ensure only one transfer is
created.
For supported endpoints, include a unique `idempotentId` in the `POST` request body.
```json theme={null}
{
"idempotentId": "9f8fbb54-7f5b-4993-829b-758b4c5f7e65"
}
```
## Retries and backoff
Retry `429` and `5xx` responses with exponential backoff—for example, 1s, 2s, 4s, then 8s. When retrying a `POST`, reuse the same `idempotentId` so a request that succeeded but didn't return its response doesn't execute twice. Don't retry other `4xx` responses: they indicate a request that needs to be corrected, not repeated.
## Pagination
Cursor pagination is used for endpoints that return multiple records. Responses
include a `next` cursor in the `page` attribute when more results are available.
```http theme={null}
GET /v2/transfers?afterId=1968b94b09b8a1a8a381775d1f04978c424d891d50e517774bf984297985b471&limit=100
```
| Parameter | Description |
| --------- | ------------------------------------------------------------------------------------------------------------------- |
| `afterId` | Request a page after, or older than, this pagination ID. |
| `endDate` | Request records older than this date in `YYYY-MM-DD` format. Used for `/trading/trades` and `/trading/settlements`. |
| `limit` | Maximum number of results requested. Defaults vary by resource. |
# Introduction
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/introduction
Introduction for the Anchorage Digital REST API v2.0
The Anchorage Digital API is a REST API that consists of 100+ operations across custody, wallets, transfers, trading, Atlas settlement, onboarding, tax, subaccounts, webhook notifications, and more.
You're viewing **Porto** API documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/api-reference/introduction)
Building with an AI assistant? Connect the Anchorage Digital docs MCP server or start from ready-made prompts. See [Build with AI](/knowledge-base/porto/build-with-ai/overview).
## Base URLs
| Environment | Base URL |
| :---------- | :-------------------------- |
| Production | `https://api.anchorage.com` |
## Send your first API call
Define which vaults and operations the API key can access. See [Permission groups](/knowledge-base/porto/developers/permission-groups).
Generate a key assigned to the permission group. See [API keys](/knowledge-base/porto/developers/api-keys).
Sensitive endpoints require an Ed25519 signature in addition to the API key. See [Request signing](/knowledge-base/porto/developers/request-signing).
Include your API key in the `Api-Access-Key` header on every request. Add `Api-Signature` and `Api-Timestamp` on sensitive endpoints.
```bash theme={null}
curl -X GET \
'https://api.anchorage-staging.com/v2/apikey' \
-H 'Api-Access-Key: ' \
-H 'Api-Signature: ' \
-H 'Api-Timestamp: '
```
## Next steps
Learn how requests are signed and attached to headers.
Learn how requests are signed and attached to headers.
Handle response codes, rate limits, and cursor pagination.
# List all addresses for an asset
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/addresses/list-all-addresses-for-an-asset
/knowledge-base/openapi/v2.yaml get /vaults/{vaultId}/addresses
Permissions required: **Read vault activity** or **Create address**
Get all addresses for the asset type within the specified `vaultId`.
# Provision a deposit address for a wallet
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/addresses/provision-a-deposit-address-for-a-wallet
/knowledge-base/openapi/v2.yaml post /wallets/{walletId}/addresses
Permissions required: **Create address**
This endpoint allows you to request an asynchronous provision of a signed deposit address for a given wallet. For UTXO-based wallets a new address will always be provisioned upon request. For account-based wallets only one address may be provisioned per wallet and subsequent attempts will return the previously provisioned address.
Newly requested addresses may not be available for several minutes once requested.
# List information for current API key
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/api-key/list-information-for-current-api-key
/knowledge-base/openapi/v2.yaml get /apikey
Permissions required: none
Get the user information for your API key.
As with any endpoint, a signature included in the request will be validated. This can be used to confirm the associated signing key as well information about the current API key.
# List supported asset types
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/asset-types/list-supported-asset-types
/knowledge-base/openapi/v2.yaml get /asset-types
Permissions required: none
List all of the supported asset types for your organization. Each asset type object includes the name of the asset (ex. Bitcoin) as well as the asset type (ex. BTC), which usually corresponds to the asset's ticker symbol.
#### Filters
You may optionally supply the following filters:
- Specify the `asset types` to filter the organization asset types. Multiple asset types should be separated by commas.
For example:
To filter a single asset type to only Bitcoin we can use /v2/asset-types?assetTypes=BTC
To filter multiple asset types for instance Bitcoin and Ethereum we could use /v2/asset-types?assetTypes=BTC,ETH
- Specify the `feature types` to filter the organization asset types. Multiple features should be separated by commas.
For example:
To filter all organization assets that have the HOLD feature we can use /v2/asset-types?assetFeatures=HOLDS
To filter all organization assets that have the HOLD or TRANSFERS feature we can use /v2/asset-types?assetFeatures=HOLDS,TRANSFERS
# Accept a settlement
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/atlas-settlement-network/accept-a-settlement
/knowledge-base/openapi/v2.yaml post /atlas/settlements/{settlementId}/accept
Permissions required: **Propose and Accept settlements** and **Read vault activity**
Accept a proposed settlement and select wallets to receive funds to and/or send funds from.
# Authorize a settlement
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/atlas-settlement-network/authorize-a-settlement
/knowledge-base/openapi/v2.yaml post /atlas/settlements/{settlementId}/authorize
Permissions required: **Authorize Settlements**
After your participant has proposed a settlement or accepted a settlement proposal, the details of the settlement must be authorized.
To authorize via API, the API key must have a special permission. Otherwise, authorization takes place in the app according to organization policy.
# Get a counterparty by ID
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/atlas-settlement-network/get-a-counterparty-by-id
/knowledge-base/openapi/v2.yaml get /atlas/directory/counterparties/{counterpartyId}
Permissions required: **Read vault activity**
Get a single trusted counterparty by its ID.
# Get a participant by ID
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/atlas-settlement-network/get-a-participant-by-id
/knowledge-base/openapi/v2.yaml get /atlas/directory/participants/{participantId}
Permissions required: **Read vault activity**
Get a single participant by its ID.
# Get a settlement by ID
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/atlas-settlement-network/get-a-settlement-by-id
/knowledge-base/openapi/v2.yaml get /atlas/settlements/{settlementId}
Permissions required: **Read vault activity**
Get a single settlement by its ID.
# List participants
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/atlas-settlement-network/list-participants
/knowledge-base/openapi/v2.yaml get /atlas/directory/participants
Permissions required: **Read vault activity**
Get the list of participants you have access to.
# List settlements
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/atlas-settlement-network/list-settlements
/knowledge-base/openapi/v2.yaml get /atlas/settlements
Permissions required: **Read vault activity**
Get settlements proposed by you or proposed to you.
# List trusted counterparties
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/atlas-settlement-network/list-trusted-counterparties
/knowledge-base/openapi/v2.yaml get /atlas/directory/counterparties
Permissions required: **Read vault activity**
Get trusted counterparties.
# Propose a settlement
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/atlas-settlement-network/propose-a-settlement
/knowledge-base/openapi/v2.yaml post /atlas/settlements
Permissions required: **Propose and Accept settlements**
Propose a settlement with a counterparty for a list of assets coming from and/or arriving into wallets owned by your participant.
Positive amounts indicate funds to be received and negative amounts indicate funds to be sent.
```json
[
{
"walletId": "d4578f401daadff65615236c5ad1e12c",
"quantity": "-1.1",
"assetType": "BTC"
},
{
"walletId": "43a9aeac02c851f4868f9d89aabde494",
"quantity": "20.62",
"assetType": "ETH"
}
]
```
For example, the above wallet amounts indicate you will send 1.1 BTC from your wallet `d4578f401daadff65615236c5ad1e12c` and receive 20.62 ETH into your wallet `43a9aeac02c851f4868f9d89aabde494`.
The steps to create a settlement are:
1. The proposer participant proposes it, selecting an acceptor, assets, amounts and wallets.
2. The proposer authorizes it, either through the API or mobile app signing.
3. The acceptor participant accepts it, selecting wallets to use.
4. (optional) The acceptor authorizes it, either through the API or mobile app signing.
5. The settlement is funded in the sending wallets.
6. The assets are transferred on-chain, as directed by the settlement.
Steps 2 or 3 can happen out of order.
Step 4 is skipped if the acceptor is not sending any assets.
The settlement stays in the `ActionNeeded` state until it reaches step 6. Then it enters the `Executing` state and, after that, it enters one of the final states.
# Propose a trusted counterparty
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/atlas-settlement-network/propose-a-trusted-counterparty
/knowledge-base/openapi/v2.yaml post /atlas/directory/counterparties
Permissions required: **Propose Trusted Counterparty**
Propose adding a new trusted counterparty for a participant.
# Reject a settlement proposal
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/atlas-settlement-network/reject-a-settlement-proposal
/knowledge-base/openapi/v2.yaml post /atlas/settlements/{settlementId}/reject
Permissions required: **Propose and Accept settlements** or **Authorize Settlements**
Rejects a proposed settlement for your Atlas participant. Proposed settlements cannot be rejected if they have already been authorized.
# Request a collateral decrease
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/collateral-decrease
POST /collateral_management/packages/{packageId}/collateral-decrease
Request a collateral decrease for a package.
# Create a new collateral package
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/collateral-management/create-a-new-collateral-package
/knowledge-base/openapi/v2.yaml post /collateral_management/packages
Permissions required: **Manage Collateral Packages** and **Read vault activity**
Creates a new collateral package in the Collateral Management service.
# Create a new exposure
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/collateral-management/create-a-new-exposure
/knowledge-base/openapi/v2.yaml post /collateral_management/exposures
Permissions required: **Manage Collateral Exposures** and **Read vault activity**
Creates a new exposure in the Collateral Management service.
# Create a new operation
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/collateral-management/create-a-new-operation
/knowledge-base/openapi/v2.yaml post /collateral_management/operations
Permissions required: **Manage Collateral Packages** and **Read vault activity**
Create a new operation in the Collateral Management service.
# List collateral and exposure operations
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/collateral-management/list-collateral-and-exposure-operations
/knowledge-base/openapi/v2.yaml get /collateral_management/operations
Permissions required: **Read vault activity**
Get all the operations that were booked for collateral packages and exposures.
# List exposures
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/collateral-management/list-exposures
/knowledge-base/openapi/v2.yaml get /collateral_management/exposures
Permissions required: **Read vault activity**
Get Exposures.
# List packages
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/collateral-management/list-packages
/knowledge-base/openapi/v2.yaml get /collateral_management/packages
Permissions required: **Read vault activity**
Get collateral packages.
# Update a collateral package
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/collateral-management/update-a-collateral-package
/knowledge-base/openapi/v2.yaml patch /collateral_management/packages/{packageId}
Permissions required: **Manage Collateral Packages** and **Read vault activity**
Updates an existing collateral package in the Collateral Management service.
# Update an operation
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/collateral-management/update-an-operation
/knowledge-base/openapi/v2.yaml patch /collateral_management/operations/{operationId}
Permissions required: **Manage Collateral Packages** and **Read vault activity**
Update an existing operation in the Collateral Management service.
Only the fields provided in the request body will be updated.
# Get collateral price sources
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/collateral-price-sources
GET /collateral_management/price_sources
Get available assets for specific price sources.
# Attribute a deposit
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/deposit-attribution/attribute-a-deposit
/knowledge-base/openapi/v2.yaml patch /deposit-attributions/{depositTransactionId}
Permissions required: **Deposit Attribution**.
Attribute a deposit by providing information about the originator.
Only attributions in `PENDING` status can be attributed.
Once the attribution is successfully performed the attribution status moves from `PENDING` to `UNDER_REVIEW`.
For attributions performed via API the attributionType will always be `CLIENT_API`.
# Attribute a deposit as spam
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/deposit-attribution/attribute-a-deposit-as-spam
/knowledge-base/openapi/v2.yaml post /deposit-attributions/{depositTransactionId}/spam
Permissions required: **Deposit Attribution**.
Attribute a deposit as spam.
Only attributions in `PENDING` status can be attributed.
Once the attribution is successfully performed the attribution status moves from `PENDING` to `ATTRIBUTED`.
For any spam attribution performed via API, the attributionType will automatically be set to `SPAM` and the deposit's funds will cease to be available.
# List deposit attributions
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/deposit-attribution/list-deposit-attributions
/knowledge-base/openapi/v2.yaml get /deposit-attributions/attributions
Permissions required: **Read Deposit Attribution** or **Deposit Attribution**.
Returns all Deposit Attributions for an Organization based on the provided query parameters.
Default sorting will be ascending order by createdAt.
# Off-chain vesting schedules
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/offchainvesting-schedules
GET /offchainvesting/schedules
Retrieve off-chain vesting schedules.
# Begin new customer onboarding application
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/onboarding/begin-new-customer-onboarding-application
/knowledge-base/openapi/v2.yaml post /onboarding/customers
Permissions required: **Onboarding**
Initiate onboarding application for a new customer of Anchorage Digital
# Begin new customer subaccount onboarding application
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/onboarding/begin-new-customer-subaccount-onboarding-application
/knowledge-base/openapi/v2.yaml post /onboarding/subaccounts
Permissions required: **Onboarding**
Initiate onboarding application for a new customer subaccount of Anchorage Digital
# Creates a new agreement questionnaire of the given agreementType
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/onboarding/creates-a-new-agreement-questionnaire-of-the-given-agreementtype
/knowledge-base/openapi/v2.yaml post /onboarding/agreements/{agreementType}
Permissions required: **Onboarding**
Creates a new agreement questionnaire
# Request a signed URL for document image upload
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/onboarding/request-a-signed-url-for-document-image-upload
/knowledge-base/openapi/v2.yaml post /onboarding/customers/{customerId}/document
Permissions required: **Onboarding**
Request a signed URL for uploading document images for the existing customer onboarding application
Note that the URL expires after 15m, you can still generate a new URL if this one expires. If the image file is never uploaded, the document will show as missing in the `GET` response and a new signed URL must be requested.
# Retrieve uploaded data and status of all customers onboarding
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/onboarding/retrieve-uploaded-data-and-status-of-all-customers-onboarding
/knowledge-base/openapi/v2.yaml get /onboarding/customers
Permissions required: **Onboarding**
List all customers onboarding application status, missing information and previously uploaded information.
# Retrieve uploaded data and status of all onboarding customer subaccounts
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/onboarding/retrieve-uploaded-data-and-status-of-all-onboarding-customer-subaccounts
/knowledge-base/openapi/v2.yaml get /onboarding/subaccounts
Permissions required: **Onboarding**
List all customer subaccounts onboarding application status, missing information and previously uploaded information.
# Retrieve uploaded data and status of customer onboarding
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/onboarding/retrieve-uploaded-data-and-status-of-customer-onboarding
/knowledge-base/openapi/v2.yaml get /onboarding/customers/{customerId}
Permissions required: **Onboarding**
Get customer onboarding application status, missing information and previously uploaded information.
# Retrieve uploaded data and status of customer subaccount onboarding
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/onboarding/retrieve-uploaded-data-and-status-of-customer-subaccount-onboarding
/knowledge-base/openapi/v2.yaml get /onboarding/subaccounts/{subaccountId}
Permissions required: **Onboarding**
Get customer subaccount onboarding application status, missing information and previously uploaded information.
# Retrieves all the agreements questionnaires for the specified agreement type
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/onboarding/retrieves-all-the-agreements-questionnaires-for-the-specified-agreement-type
/knowledge-base/openapi/v2.yaml get /onboarding/agreements/{agreementType}
Permissions required: **Onboarding**
Retrieves all the agreements questionnaires for the specified agreement type
# Retrieves the agreement questionnaire of the given agreement type and agreement ID
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/onboarding/retrieves-the-agreement-questionnaire-of-the-given-agreement-type-and-agreement-id
/knowledge-base/openapi/v2.yaml get /onboarding/agreements/{agreementType}/{agreementId}
Permissions required: **Onboarding**
Retrieves the agreement questionnaire for the specified agreement type and agreement ID
# Submit a completed customer onboarding application
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/onboarding/submit-a-completed-customer-onboarding-application
/knowledge-base/openapi/v2.yaml post /onboarding/customers/{customerId}/submit
Permissions required: **Onboarding**
Indicate that a customer onboarding application is complete and can be submitted for screening
# Submit a completed customer subaccount onboarding application
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/onboarding/submit-a-completed-customer-subaccount-onboarding-application
/knowledge-base/openapi/v2.yaml post /onboarding/subaccounts/{subaccountId}/submit
Permissions required: **Onboarding**
Indicate that a customer subaccount onboarding application is complete and can be submitted for screening
# Update customer onboarding application
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/onboarding/update-customer-onboarding-application
/knowledge-base/openapi/v2.yaml put /onboarding/customers/{customerId}
Permissions required: **Onboarding**
Update an existing customer onboarding application. The application data will be updated to match the entries of the update payload. If any field is invalid, the entire update will fail and no data will be updated.
# Update customer subaccount onboarding application
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/onboarding/update-customer-subaccount-onboarding-application
/knowledge-base/openapi/v2.yaml put /onboarding/subaccounts/{subaccountId}
Permissions required: **Onboarding**
Update data of an existing customer subaccount onboarding application
# Create a Stablecoin Conversion
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/stablecoins/create-a-stablecoin-conversion
/knowledge-base/openapi/v2.yaml post /stablecoins/conversion
Permissions required: **Convert Stablecoins**
Create a stablecoin conversion, either issuance or redemption. Issuance is when USD is converted to the stablecoin. Redemption is when the stablecoin asset is converted to USD.
# Get Issue/Redeem History
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/stablecoins/get-issueredeem-history
/knowledge-base/openapi/v2.yaml get /stablecoins/history
Permissions required: **Convert Stablecoins**
Retrieve the history of stablecoin issuance and redemption operations for your organization.
Results are paginated and ordered by creation time (newest first).
# Get Stablecoin Reserves Entitled Stablecoins
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/stablecoins/get-stablecoin-reserves-entitled-stablecoins
/knowledge-base/openapi/v2.yaml get /stablecoins/reserves/entitled-stablecoins
Permissions required: **Read vault activity**
List the stablecoins whose reserves history your organization is entitled to view. Pass any returned symbol as the `stablecoin` query parameter to `GET /stablecoins/reserves` to retrieve that stablecoin's daily reserves reconciliation history. Returns an empty array when your organization cannot view reserves history for any stablecoin.
# Get Stablecoin Reserves History
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/stablecoins/get-stablecoin-reserves-history
/knowledge-base/openapi/v2.yaml get /stablecoins/reserves
Permissions required: **Read vault activity**
Retrieve the daily reserves reconciliation history for a stablecoin your organization is entitled to.
Results are paginated and ordered by creation time (newest first).
# Download a statement
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/statement-download
GET /statements/{statementId}/download
Download a statement.
# Get statement
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/statement-get
GET /statements/{statementId}
Get a statement.
# List statement types
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/statement-types
GET /statement-types
List statement types.
# List statements
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/statements-list
GET /statements
List statements.
# Cancel Manual Billing Charge
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/subaccounts/cancel-manual-billing-charge
/knowledge-base/openapi/v2.yaml delete /subaccounts/billing/charges/{chargeId}
Permissions required: **Subaccount**
Cancel Manual Billing Charge
# Cancels a Withdrawal Request for a subaccount
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/subaccounts/cancels-a-withdrawal-request-for-a-subaccount
/knowledge-base/openapi/v2.yaml delete /subaccounts/{subaccountId}/fiat/withdrawals/{transactionId}
Permissions required: **Subaccount**
Cancels a Withdrawal Request
# Create a new subaccount for a given program customer
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/subaccounts/create-a-new-subaccount-for-a-given-program-customer
/knowledge-base/openapi/v2.yaml post /subaccounts/customers/{customerId}/accounts
Permissions required: **Subaccount**
Open a new subaccount for the program customer
DEPRECATED, please use /onboarding/accounts
# Create a USD Withdrawal Request for a subaccount
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/subaccounts/create-a-usd-withdrawal-request-for-a-subaccount
/knowledge-base/openapi/v2.yaml post /subaccounts/{subaccountId}/fiat/withdrawals
Permissions required: **Subaccount**
Creates a USD Withdrawal Request for an Asset within a Subaccount (FIAT only for now)
This will trigger an e-mail to be sent to the program customer to authorize the withdrawal.
# Create Manual Billing Charge
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/subaccounts/create-manual-billing-charge
/knowledge-base/openapi/v2.yaml post /subaccounts/billing/charges
Permissions required: **Subaccount**
Create Manual Billing Charge
# Create new allocations
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/subaccounts/create-new-allocations
/knowledge-base/openapi/v2.yaml post /subaccounts/transactions/allocations
Permissions required: **Subaccount**
Create new allocation of pre-funded values between the Funding and Program Customers' subaccounts. This is a transactional operation, all transactions will be created successfully or none will.
# Create new transactions
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/subaccounts/create-new-transactions
/knowledge-base/openapi/v2.yaml post /subaccounts/transactions
Permissions required: **Subaccount**
Create new transactions between subaccounts of the same Program Customer. This is a transactional operation, all transactions will be created successfully or none will.
# Fetches a set of filtered transactions allocations
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/subaccounts/fetches-a-set-of-filtered-transactions-allocations
/knowledge-base/openapi/v2.yaml get /subaccounts/transactions/allocations
Permissions required: **Subaccount** or **Read Subaccount**
Retrieves a filtered set of transactions that are connected to funding allocations.
# Fetches a set of Withdrawals Requests for a subaccount
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/subaccounts/fetches-a-set-of-withdrawals-requests-for-a-subaccount
/knowledge-base/openapi/v2.yaml get /subaccounts/{subaccountId}/fiat/withdrawals
Permissions required: **Subaccount** or **Read Subaccount**
Retrieves a filtered set of Withdrawal Requests within a Subaccount (FIAT only for now).
# Get list of transactions filter by ID
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/subaccounts/get-list-of-transactions-filter-by-id
/knowledge-base/openapi/v2.yaml get /subaccounts/transactions/{transactionsIds}
Permissions required: **Subaccount** or **Read Subaccount**
Return the requested transactions, sorted by the creation date, the client has access too
# Get USD Withdrawal Request for a subaccount
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/subaccounts/get-usd-withdrawal-request-for-a-subaccount
/knowledge-base/openapi/v2.yaml get /subaccounts/{subaccountId}/fiat/withdrawals/{transactionId}
Permissions required: **Subaccount**
Get a USD Withdrawal Request
# List all subaccounts
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/subaccounts/list-all-subaccounts
/knowledge-base/openapi/v2.yaml get /subaccounts/customers/accounts
Permissions required: **Subaccount** or **Read Subaccount**
Return all subaccounts associated for an organization
# List all transactions
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/subaccounts/list-all-transactions
/knowledge-base/openapi/v2.yaml get /subaccounts/transactions
Permissions required: **Subaccount** or **Read Subaccount**
Return all the transactions, sorted by the creation date, the client has access to
# List subaccounts
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/subaccounts/list-subaccounts
/knowledge-base/openapi/v2.yaml get /subaccounts/customers/{customerId}/accounts
Permissions required: **Subaccount** or **Read Subaccount**
Return all subaccounts associated to a customerId
# Return bank information for a subaccount
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/subaccounts/return-bank-information-for-a-subaccount
/knowledge-base/openapi/v2.yaml get /subaccounts/accounts/{subaccountId}/bank-info
Permissions required: **Subaccount** or **Read Subaccount**
Return bank information for a subaccount
# Return wallets linked to a subaccount
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/subaccounts/return-wallets-linked-to-a-subaccount
/knowledge-base/openapi/v2.yaml get /subaccounts/accounts/{subaccountId}/wallets
Permissions required: **Subaccount** or **Read Subaccount**
Return wallets linked to a subaccount
# Update an existing subaccount
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/subaccounts/update-an-existing-subaccount
/knowledge-base/openapi/v2.yaml patch /subaccounts/accounts/{subaccountId}
Permissions required: **Subaccount**
Update a subaccount
# Apply tags to an entity
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/tagging/apply-tags-to-an-entity
/knowledge-base/openapi/v2.yaml post /tags/apply
Apply a set of tags to an entity, replacing the entity's existing tags of the given tag type. Tags are auto-created if they do not exist, and an empty list clears the entity's tags of that type.
# List tags
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/tagging/list-tags
/knowledge-base/openapi/v2.yaml get /tags
List tags filtered by ownership type and/or entity. When entityId is provided, returns tags applied to that entity. When type is provided, filters tag definitions by ownership type.
# Remove a tag from an entity
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/tagging/remove-a-tag-from-an-entity
/knowledge-base/openapi/v2.yaml delete /tags/apply/{entityId}/{tagName}
Remove a specific tag from an entity. Tag name matching is case-insensitive.
# Search entities by tag
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/tagging/search-entities-by-tag
/knowledge-base/openapi/v2.yaml get /tags/search
Search for entities that have specific tags applied. Supports cursor-based pagination.
# List deposit transactions for account
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/tax-account-transactions
GET /tax/accounts/{accountId}/transactions
List deposit transactions for a tax account.
# List tax accounts
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/tax-accounts
GET /tax/accounts
List tax accounts.
# Update deposit transaction cost basis
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/tax-transaction-cost-basis
PATCH /tax/accounts/{accountId}/transactions/{transactionId}
Update the cost basis of a deposit transaction.
# Add Tag to Transaction
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/tax/add-tag-to-transaction
/knowledge-base/openapi/v2.yaml post /tax/transaction/{transactionId}/tag
Permissions required: **Subaccount**
Tag a prior transaction for tax purposes.
** Under development **
# Get Program Customer Tax Forms
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/tax/get-program-customer-tax-forms
/knowledge-base/openapi/v2.yaml get /tax/clients/{customerId}/forms
Permissions required: **Subaccount**
Get a program customer's generated tax forms
# Get Subaccount Tax Forms
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/tax/get-subaccount-tax-forms
/knowledge-base/openapi/v2.yaml get /tax/subaccounts/{subaccountId}/forms
Permissions required: **Subaccount**
Get subaccount's generated tax forms
# List Gains
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/tax/list-gains
/knowledge-base/openapi/v2.yaml get /tax/gains/summary/{subaccountId}
Permissions required: **Subaccount**
List subaccount's gains for a period breakdown to short term, long term and total
# List Gains Cost Basis
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/tax/list-gains-cost-basis
/knowledge-base/openapi/v2.yaml get /tax/gains/costbasis/{subaccountId}
Permissions required: **Subaccount**
List subaccount's breakdown of combined cost basis, proceeds and gains/losses
# List of the Inventory for an asset
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/tax/list-of-the-inventory-for-an-asset
/knowledge-base/openapi/v2.yaml get /tax/inventory/{subaccountId}/{assetTypeId}
Permissions required: **Subaccount**
List user's inventory for an asset.
# List summary of Inventory
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/tax/list-summary-of-inventory
/knowledge-base/openapi/v2.yaml get /tax/inventory/summary/{subaccountId}
Permissions required: **Subaccount**
List user's inventory summary for all assets.
# List Transactions
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/tax/list-transactions
/knowledge-base/openapi/v2.yaml get /tax/transactions/{subaccountId}
Permissions required: **Subaccount**
List tax transactions of a subaccount.
# Remove Tag from Transaction
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/tax/remove-tag-from-transaction
/knowledge-base/openapi/v2.yaml delete /tax/transaction/{transactionId}/tag
Permissions required: **Subaccount**
Remove tax tag for a prior transaction.
** Under development **
# Update Transaction Cost Basis
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/tax/update-transaction-cost-basis
/knowledge-base/openapi/v2.yaml patch /tax/transaction/{transactionId}
Permissions required: **Subaccount**
Update the cost basis for a deposit or withdraw transaction.
# Accept a quote
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/trading/accept-a-quote
/knowledge-base/openapi/v2.yaml post /trading/quote/accept
Permissions required: **Execute trades**
Accept a quote by its quoteID and side.
#### Idempotent Requests
This endpoint supports [idempotent requests](#section/Idempotency) so that a quote cannot be accepted twice if an API call was interrupted and is retried. To send an idempotent request, include the `idempotentId` field in the body of the POST request.
# Cancel an async order
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/trading/cancel-an-async-order
/knowledge-base/openapi/v2.yaml post /trading/async-order/cancel
Permissions required: **Execute trades**
Cancels an async order.
# Get a trading account by id
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/trading/get-a-trading-account-by-id
/knowledge-base/openapi/v2.yaml get /trading/accounts/{accountId}
Permissions required: **Read trade activity**
Get trading account details by ID.
# Get market data snapshot
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/trading/get-market-data-snapshot
/knowledge-base/openapi/v2.yaml get /trading/marketdata
Permissions required: **Execute trades** or **Read trade activity**
Get real-time market data snapshot for a trading symbol from the liquidity provider.
# Get order by ID
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/trading/get-order-by-id
/knowledge-base/openapi/v2.yaml get /trading/orders/{orderId}
Permissions required: **Read trade activity** or **Execute trades** (if order created by this API key)
Get order by ID, where the ID can be anchorage generated orderId or clientOrderId
# Get settlement by ID
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/trading/get-settlement-by-id
/knowledge-base/openapi/v2.yaml get /trading/settlements/{settlementId}
Permissions required: **Execute trades** or **Read trade activity**
Get settlement details by ID.
# Get trade by ID
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/trading/get-trade-by-id
/knowledge-base/openapi/v2.yaml get /trading/trades/{tradeId}
Permissions required: **Read trade activity** or **Execute trades** (if trade created by this API key)
Get trade by ID.
# Get trading account credit limit and usage
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/trading/get-trading-account-credit-limit-and-usage
/knowledge-base/openapi/v2.yaml get /trading/accounts/{accountId}/credit
Permissions required: **Read trade activity**
Get the credit limit and usage of a trading account per asset.
Current USD prices are not returned, only assets and their quantity.
Still under development, return empty replies.
# List orders
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/trading/list-orders
/knowledge-base/openapi/v2.yaml get /trading/orders
Permissions required: **Execute trades** or **Read trade activity**
List all orders. With the permission **Read trade activity** all orders of the organization may be read. With the permission **Execute trades** only the orders created by this API key may be read.
Orders are sorted in a descending order by their timestamp, i.e. the most recent order or the order with a timestamp closest to `endDate` is listed first.
When filtering by `subaccountId`, the allocation information is included but filtered to show only the allocation for the requested subaccount.
For multi-order requests without a subaccount filter, allocation information is not included.
To get complete allocation information, use [GET `/v2/trading/orders/{orderId}`](#tag/Trading/operation/getOrderStatus)
#### Filters
You may optionally supply filters for the list of orders using query parameters below
# List outstanding trading positions
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/trading/list-outstanding-trading-positions
/knowledge-base/openapi/v2.yaml get /trading/positions
Permissions required: **Execute trades** or **Read trade activity**
Get the list of outstanding trading positions.
# List settlements
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/trading/list-settlements
/knowledge-base/openapi/v2.yaml get /trading/settlements
Permissions required: **Execute trades** or **Read trade activity**
List of all settlements. With permission **Read trade activity** all settlements of the organization may be read. With permission **Execute trades** only settlements this api key has created may be read.
Settlements are sorted in a descending order by their timestamp, i.e. the most recent settlement or the settlement with a timestamp closest to `endDate` is listed first.
#### Filters
You may optionally supply the following filters:
- Specify a one or multiple `status` to filter settlements. Multiple statuses should be separated by commas.
# List supported trading pairs
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/trading/list-supported-trading-pairs
/knowledge-base/openapi/v2.yaml get /trading/pairs
Permissions required: **Execute trades** or **Read trade activity**
List all of the supported trading pairs for your organization.
Each trading pair object includes a description and trading
symbol (ex. BTC-USD), which usually corresponds to two asset ticker symbols.
Optionally, a trading pair object includes a reference data object that details the trading precision context: minimum size increment and price increment.
# List trades
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/trading/list-trades
/knowledge-base/openapi/v2.yaml get /trading/trades
Permissions required: **Execute trades** or **Read trade activity**
List all trades. With the permission **Read trade activity** all trades of the organization may be read. With the permission **Execute trades** only the trades created by this API key may be read.
Trades are sorted in a descending order by their timestamp, i.e. the most recent trade or the trade with a timestamp closest to `endDate` is listed first.
#### Filters
You may optionally supply the following filters:
- Specify a `tradingPair` to filter by the trading pair of the trade, for example `BTC-USD`.
- Specify one or multiple `status` to filter trades. Multiple statuses should be separated by commas.
- Specify a `side` to filter by the side of the trade.
# List trades by settlement
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/trading/list-trades-by-settlement
/knowledge-base/openapi/v2.yaml get /trading/settlements/{settlementId}/trades
Permissions required: **Execute trades** or **Read trade activity**
List trades for the provided settlement. With the permission **Read trade activity** all trades of the organization may be read. With the permission **Execute trades** only the trades created by this API key may be read.
Trades are sorted in a descending order by their timestamp (i.e. the most recent trade or the trade with a timestamp closest to `endDateTime` is listed first).
# List trading account balances
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/trading/list-trading-account-balances
/knowledge-base/openapi/v2.yaml get /trading/accounts/{accountId}/balances
Permissions required: **Read trade activity**
Get the trading account balances of fiat and digital assets
# List trading accounts
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/trading/list-trading-accounts
/knowledge-base/openapi/v2.yaml get /trading/accounts
Permissions required: **Read trade activity**
Get the list of trading accounts
# Place an async order
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/trading/place-an-async-order
/knowledge-base/openapi/v2.yaml post /trading/async-order
Permissions required: **Execute trades**
Place an order, either Limit, StopLoss, StopLimit or TakeProfitLimit currently FillOrKill, ImediateOrCancel or GoodTillCancel are supported.
One of `accountId` or `subaccountId` must be specified but not both.
# Place an order
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/trading/place-an-order
/knowledge-base/openapi/v2.yaml post /trading/order
Permissions required: **Execute trades**
Place an order, either Market or Limit, currently only FillOrKill is supported.
One of `accountId` or `subaccountId` must be specified but not both.
# Request a quote
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/trading/request-a-quote
/knowledge-base/openapi/v2.yaml post /trading/quote
Permissions required: **Execute trades**
Request a quote
#### Idempotent Requests
This endpoint supports [idempotent requests](#section/Idempotency) so that quote is not requested twice if an API call was interrupted and must be retried. To send an idempotent request, include the `idempotentId` field in the body of the POST request.
# Create a collect request
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/transactions/create-a-collect-request
/knowledge-base/openapi/v2.yaml post /transactions/collect
Permissions required: **Initiate Staking and Unstaking**
In staking, the "collect" operation is the action of claiming inactive unstaked amount back to
the available balance by moving them from the staking protocol or pool into a personal wallet. Once collected, these amounts are fully under wallet's owner control.
*NOTE: This endpoint is under development.*
# Create a consolidate stake request
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/transactions/create-a-consolidate-stake-request
/knowledge-base/openapi/v2.yaml post /transactions/consolidate-stake
Permissions required: **Initiate Staking and Unstaking**
Consolidate a source staking position into a target staking position.
Only supported for Ethereum 0x02 validators.
# Create a stake request
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/transactions/create-a-stake-request
/knowledge-base/openapi/v2.yaml post /transactions/stake
Permissions required: **Initiate Staking and Unstaking**
#### Identify the sending asset
To initiate a staking operation, you must identify which asset you'd like to stake funds from. Provide a `source` and `assetType`.
#### Permissions
The provided API key must be associated with a [permission group](#section/Authentication-and-Security/Permission-Groups) that has Initiate Staking and Unstaking permission for the sending vault.
#### Additional Metadata
You may provide a `description` with each staking operation, that will be visible within your organization in the Anchorage Digital iOS Application.
#### Successful Staking
If the stake request is valid, the request will initiate a stake transaction from the sending wallet. It will still require a quorum of approvals on the Anchorage Digital iOS app and will undergo manual Anchorage Digital Risk Review. Like other transactions, these will be visible on the Anchorage Digital iOS Application, the Web Dashboard, and in the [list transactions](#operation/getTransactions) API endpoint.
#### Unsuccessful Stakes
A stake request may fail for any of the following reasons:
- An ongoing stake already exists
- The specified asset does not exist
- The specified amount exceeds the available funds for this asset (insufficient funds)
- The provided API key does not have permissions to initiate staking from this vault
If the initiated stake is approved by the quorum, the transaction may fail for any of the following reasons:
- There are insufficient funds to pay the blockchain network fee at the time of this transaction
- There is a failure on the blockchain
#### Feature under development
Currently, specific assets parameters are under development and will not be considered in any staking request. These include:
- Solana staking;
- ETH Pectra staking.
# Create a withdrawal request
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/transactions/create-a-withdrawal-request
/knowledge-base/openapi/v2.yaml post /transactions/withdrawal
Permissions required: **Initiate withdrawals**
#### Identify the sending asset
To initiate a withdrawal from a wallet to an external destination, you must identify which asset you'd like to withdraw funds from. Provide a `source` (with `id` and `type`).
#### Identify the receiving resource
Choose a resource to receive the funds as the `destination`. This resource may belong to your organization (wallet) or another organization (address, standing instruction).
#### Permissions
The provided API key must be associated with a [permission group](#section/Authentication-and-Security/Permission-Groups) that has Initiate withdrawals permission for the sending vault.
#### Additional Metadata
You may provide a `description` with each withdrawal, that will be visible within your organization in the Anchorage Digital iOS Application.
#### Successful Withdrawals
If the withdrawal request is valid, the request will initiate a withdrawal transaction from the sending wallet. This is a common withdrawal that, unlike Transfers, will still require a quorum of approvals on the Anchorage Digital iOS app and will undergo manual Anchorage Digital Risk Review. Like other transactions, these withdrawals will be visible on the Anchorage Digital iOS Application, the Web Dashboard, and in the [list transactions](#operation/getTransactions) API endpoint.
#### Unsuccessful Withdrawals
A withdrawal request may fail for any of the following reasons:
- An ongoing withdrawal already exists (unlike transfers, withdrawal requests are not queued)
- The specified asset does not exist
- The specified amount exceeds the available funds for this asset (insufficient funds)
- The destination address is invalid
- The provided API key does not have permissions to initiate withdrawals from this wallet
If the initiated withdrawal is approved by the quorum, the transaction may fail for any of the following reasons:
- There are insufficient funds to pay the blockchain network fee at the time of this transaction
- There is a failure on the blockchain
# Create an unstake request
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/transactions/create-an-unstake-request
/knowledge-base/openapi/v2.yaml post /transactions/unstake
Permissions required: **Initiate Staking and Unstaking**
#### Identify the sending asset
To initiate an unstake transaction, you must identify which asset you'd like to unstake funds from. Provide a `source` and `assetType`.
#### Permissions
The provided API key must be associated with a [permission group](#section/Authentication-and-Security/Permission-Groups) that has Initiate Staking and Unstaking permission for the sending vault.
#### Additional Metadata
You may provide a `description` with each stake, that will be visible within your organization in the Anchorage Digital iOS Application.
#### Successful Unstakes
If the stake request is valid, the request will initiate a stake transaction from the sending wallet. It will still require a quorum of approvals on the Anchorage Digital iOS app and will undergo manual Anchorage Digital Risk Review. Like other transactions, these will be visible on the Anchorage Digital iOS Application, the Web Dashboard, and in the [list transactions](#operation/getTransactions) API endpoint.
#### Unsuccessful Unstakes
A unstake request may fail for any of the following reasons:
- An ongoing unstake already exists
- The specified asset does not exist
- The specified amount exceeds the available funds to unstake for this asset (insufficient funds)
- The provided API key does not have permissions to initiate staking from this vault
If the initiated stake is approved by the quorum, the transaction may fail for any of the following reasons:
- There are insufficient funds to pay the blockchain network fee at the time of this transaction
- There is a failure on the blockchain
# Get transaction by ID
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/transactions/get-transaction-by-id
/knowledge-base/openapi/v2.yaml get /transactions/{transactionId}
Permissions required: **Read vault activity**
Get transaction by ID.
# List supported delegation addresses
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/transactions/list-supported-delegation-addresses
/knowledge-base/openapi/v2.yaml get /delegation-addresses/{assetType}
Permissions required: **Initiate Staking and Unstaking**
#### Identify the sending asset
To initiate an operation, you must identify which asset you'd like to view the delegation addresses for. Provide an `assetType`.
#### Permissions
The provided API key must be associated with a [permission group](#section/Authentication-and-Security/Permission-Groups) that has Initiate Staking and Unstaking permission for the sending vault.
# List transactions
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/transactions/list-transactions
/knowledge-base/openapi/v2.yaml get /transactions
Permissions required: **Read vault activity**
List all transactions for the vaults permissioned to your API key. You can retrieve metadata about your API key from the [API Key](#tags/API-Key) endpoints.
NOTE: price and USD value information is recent but does not reflect real-time data.
**Filters**
You may optionally supply the following filters:
- Set a date range by providing the `startDate` and/or `endDate` query parameters. The date refers to the end time of a transaction: when the transaction succeeded or failed. If the date parameters are omitted, all transactions will be returned.
- Select transactions involving a specific vault by providing the `vaultId` parameter. If the `vaultId` parameter is omitted, transactions for all vaults for which your API key is permissioned will be returned.
- Filter transactions of one or more types with the `types` parameter. Multiple types should be separated by commas.
- Select transactions involving a specific wallet by providing the `walletId` parameter. If the `walletId` parameter is omitted, transactions for all vaults for which your API key is permissioned will be returned.
- Filter transactions by the receiving address with the `destinationAddress` parameter.
# Cancel a transfer request
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/transfers/cancel-a-transfer-request
/knowledge-base/openapi/v2.yaml delete /transfers/{transferId}
Permissions required: **Transfer funds**
Cancel a transfer request. Transfer requests in the `QUEUED` state can always be cancelled. Transfer requests in the `IN_PROGRESS` state can sometimes be cancelled if the request has not been broadcast on the blockchain. Trying to cancel a request that cannot be cancelled will return a `409 Conflict` error code. Transfers can only be canceled by the API key responsible for creating that transfer (either created directly via CreateTransfer or indirectly via ExecuteHold)
# Create a transfer request
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/transfers/create-a-transfer-request
/knowledge-base/openapi/v2.yaml post /transfers
Permissions required: **Transfer funds**
#### Identify the sending resource and asset
To initiate a transfer between resources, you must identify which resource you'd like to transfer funds from and the asset type to transfer. Provide a `source` and `assetType`.
#### Identify the receiving resource
Choose a resource to receive the funds as the `destination`. This resource may belong to your organization or another organization that also custodies with Anchorage Digital, or it may also be an approved blockchain address not custodied by Anchorage Digital (see [Permission Groups](#section/Authentication-and-Security/Permission-Groups) for more details). Please note: If you would like to use the Anchorage Digital API to transfer to approved blockchain addresses, please contact [api@anchorage.com](mailto:api@anchorage.com).
#### Permissions
The provided API key must be associated with a permission group that has Transfer permissions for the vault from which the assets are being sent. The receiving resource does not need Transfer permissions to receive a transfer of funds.
#### Additional Metadata
You may provide a transfer memo with each transfer. If the transfer API request is successful, a transfer transaction will be created that will include this transfer memo in the description. The resulting deposit will also include this memo.
#### Successful Transfers
If the transfer request is valid, the request will initiate a transfer transaction from the source. This is a special withdrawal that will not require a quorum of approvals and will undergo automated Anchorage Digital Risk Review. When the transaction is broadcasted and confirmed on the blockchain, a subsequent deposit will be detected for the destination. All of these transactions will be visible on the Anchorage Digital iOS Application, the Web Dashboard, and in the [list transactions](#operation/getTransactions) API endpoint.
#### Unsuccessful Transfers
A transfer request may fail for any of the following reasons:
- The specified sending resource does not exist or does not support the specified asset type
- The specified amount exceeds the available funds for this asset (insufficient funds)
- The destination does not exist or does not support the specified asset type
- The provided API key does not have permissions to initiate transfers from this wallet
If the transfer request is successful, the actual transfer transaction may fail for any of the following reasons:
- There are insufficient funds to pay the blockchain network fee at the time of this transaction
- The transfer was successfully queued but there were insufficient funds by the time it was processed
- There is a failure on the blockchain
#### Idempotent Requests
This endpoint supports [idempotent requests](#section/Idempotency) so that a transfer does not occur twice if an API call was interrupted and must be retried. To send an idempotent request, include the `idempotentId` field in the body of the POST request.
#### Queueing
Transfer requests are queued and processed in the order they were received. When transferring between wallets, multiple transfer requests may be queued for the same asset in a given wallet, but only one will be processed at a time. The other requests will remain in the `QUEUED` state until the prior transfer is completed or fails.
#### Transferring Full Balance
For assets with network fees paid in a separate asset type, transferring the full balance of an asset is no different than transferring any other amount for that asset.
For assets with network fees paid in the same asset type, transferring the full balance is not possible without specifying to the server that the fee should be deducted from the transfer amount. See the `deductFeeFromAmountIfSameType` flag of the `TransfersRequest` model for more detail.
# Get transfer by ID
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/transfers/get-transfer-by-id
/knowledge-base/openapi/v2.yaml get /transfers/{transferId}
Permissions required: **Transfer funds**
Get transfer by ID. Restricted to transfers created by your API key, unless your API key's Transfer and Read permissions both cover the transfer's vault.
NOTE: price and USD value information is recent but does not reflect real-time data.
# List transfers
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/transfers/list-transfers
/knowledge-base/openapi/v2.yaml get /transfers
Permissions required: **Transfer funds**
List transfers created by your API key. For a given vault, transfers on it created by other API keys in your organization are also included if your API key's Transfer and Read permissions both cover that vault.
**Filters**
You may optionally supply the following filters:
- Set a date range by providing the `startDate` and/or `endDate` query parameters. If the date parameters are omitted, all transfers will be returned.
- Specify a specific vault to return transfers for by specifying the `vaultId` parameter. If the `vaultId` parameter is omitted, transfers originating from all vaults will be returned. Providing both `vaultId` and `walletId` filters will result in an error.
- Specify a specific wallet to return transfers for by specifying the `walletId` parameter. If the `walletId` parameter is omitted, transfers originating from all vaults and wallets will be returned. Providing both `vaultId` and `walletId` filters will result in an error.
- Filter transfers of one or more statuses with the `statuses` parameter. Multiple statuses should be separated by commas.
**Multiple Transfers**
To fetch a specific batch of transfers, pass a comma-separated list of `transferIds` as the `transferIds` query parameter.
# Cancel Trusted Destination creation
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/trusted-destinations/cancel-trusted-destination-creation
/knowledge-base/openapi/v2.yaml delete /trusted_destinations/{creationRequestId}/cancel
Permissions required: **Manage Trusted Destinations**
Cancel ongoing creation of Trusted Destinations
# Check status of Trusted Destinations
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/trusted-destinations/check-status-of-trusted-destinations
/knowledge-base/openapi/v2.yaml get /trusted_destinations/{creationRequestId}/status
Permissions required: **Read vault activity**
Check status of Trusted Destinations
# Create new Trusted Destinations
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/trusted-destinations/create-new-trusted-destinations
/knowledge-base/openapi/v2.yaml post /trusted_destinations
Permissions required: **Manage Trusted Destinations**
Create new Trusted Destinations
# Delete Trusted Destination
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/trusted-destinations/delete-trusted-destination
/knowledge-base/openapi/v2.yaml delete /trusted_destinations/{trustedDestinationId}
Permissions required: **Manage Trusted Destinations**
Delete a Trusted Destination
# List trusted destinations
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/trusted-destinations/list-trusted-destinations
/knowledge-base/openapi/v2.yaml get /trusted_destinations
Permissions required: **Read vault activity**
List trusted destinations
# Get vault by ID
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/vaults/get-vault-by-id
/knowledge-base/openapi/v2.yaml get /vaults/{vaultId}
Permissions required: **Read vault activity**
Get vault by ID
# List vaults
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/vaults/list-vaults
/knowledge-base/openapi/v2.yaml get /vaults
Permissions required: **Read vault activity**
List vault metadata including name, ID, description, and assets.
NOTE: price and USD value information is recent but does not reflect real-time data.
# Get vesting balances
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/vesting-balances-batch
POST /vesting/balances
Get vesting balances for multiple allocations.
# Get vesting balances for an allocation
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/vesting/get-vesting-balances-for-an-allocation
/knowledge-base/openapi/v2.yaml get /vesting/balances/{allocationId}
Get vesting balances for a specific allocation ID. Returns the current balance breakdown including available, unvested, and locked amounts.
# Activate an existing wallet on additional networks
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/wallets/activate-an-existing-wallet-on-additional-networks
/knowledge-base/openapi/v2.yaml post /wallets/{walletId}/activate
Permissions required: **Create address**
Activate the existing wallet identified by `walletId` on additional networks that share the same cryptographic key derivation (e.g. EVM-compatible chains). Each entry in `compatibleNetworkIds` produces a new wallet on that network with the same address as the source.
Per-network failures are reported individually in the response without aborting the whole call: a target network that is not key-compatible with the source wallet's network, or that the organization has not enabled, returns a `FAILED` status for that entry while other entries continue.
# Create a new wallet in a vault
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/wallets/create-a-new-wallet-in-a-vault
/knowledge-base/openapi/v2.yaml post /vaults/{vaultId}/wallets
Permissions required: **Create address**
Create a wallet in the specified `vaultId`.
# List all wallets for a vault
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/wallets/list-all-wallets-for-a-vault
/knowledge-base/openapi/v2.yaml get /vaults/{vaultId}/wallets
Permissions required: **Read vault activity**
Get all wallets for the specified `vaultId`.
# List all wallets for all vaults
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/wallets/list-all-wallets-for-all-vaults
/knowledge-base/openapi/v2.yaml get /wallets
Permissions required: **Read vault activity**
List wallet metadata for the current user.
# Staking positions for a wallet
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/wallets/staking-positions-for-a-wallet
/knowledge-base/openapi/v2.yaml get /wallets/{walletId}/staking/positions
Permissions required: **Read vault activity**
Get wallet staking positions details for the specified `walletId`.
# Staking rewards for a wallet
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/wallets/staking-rewards-for-a-wallet
/knowledge-base/openapi/v2.yaml get /wallets/{walletId}/staking/rewards
Permissions required: **Read vault activity**
Get wallet rewards details for the specified `walletId`.
# Wallet details for a wallet
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/wallets/wallet-details-for-a-wallet
/knowledge-base/openapi/v2.yaml get /wallets/{walletId}
Permissions required: **Read vault activity**
Get wallet details for the specified `walletId`.
# Cancel webhook subscription
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/webhook-notifications/cancel-webhook-subscription
/knowledge-base/openapi/v2.yaml delete /webhook/endpoints/{endpointId}/subscriptions/{eventTypeId}
Permissions required: **Configure Webhooks**
Cancel a webhook subscription to stop receiving notifications for its event type in its webhook endpoint.
# Create webhook endpoint
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/webhook-notifications/create-webhook-endpoint
/knowledge-base/openapi/v2.yaml post /webhook/endpoints
Permissions required: **Configure Webhooks**
Create a new endpoint where you would like to receive webhook notifications.
# Create webhook subscriptions
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/webhook-notifications/create-webhook-subscriptions
/knowledge-base/openapi/v2.yaml post /webhook/endpoints/{endpointId}/subscriptions
Permissions required: **Configure Webhooks**
Subscribe to event types to receive notifications in a webhook endpoint.
# Get webhook endpoint config
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/webhook-notifications/get-webhook-endpoint-config
/knowledge-base/openapi/v2.yaml get /webhook/endpoints/{endpointId}
Permissions required: **Configure Webhooks**
Get the configuration details for an endpoint.
# Get webhook validation key
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/webhook-notifications/get-webhook-validation-key
/knowledge-base/openapi/v2.yaml get /webhook/validation-key
Permissions required: **Configure Webhooks**
Get key to validate webhook authenticity.
# List webhook endpoint
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/webhook-notifications/list-webhook-endpoint
/knowledge-base/openapi/v2.yaml get /webhook/endpoints
Permissions required: **Configure Webhooks**
List all of your webhook endpoints.
# List webhook endpoint subscriptions
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/webhook-notifications/list-webhook-endpoint-subscriptions
/knowledge-base/openapi/v2.yaml get /webhook/endpoints/{endpointId}/subscriptions
Permissions required: **Configure Webhooks**
List the subscriptions that you configured for a webhook endpoint.
# List webhook event types
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/webhook-notifications/list-webhook-event-types
/knowledge-base/openapi/v2.yaml get /webhook/event-types
Permissions required: **Configure Webhooks**
List the available webhook event types that you can subscribe to.
# Update webhook endpoint
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v2/webhook-notifications/update-webhook-endpoint
/knowledge-base/openapi/v2.yaml patch /webhook/endpoints/{endpointId}
Permissions required: **Configure Webhooks**
Update the configuration for an endpoint.
# List Addresses
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v3/addresses/list-addresses
/knowledge-base/openapi/v3.yaml get /addresses
Permissions required: **Read vault activity**
List all addresses across wallets in the organization.
# Validate Destination Address
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v3/addresses/validate-destination-address
/knowledge-base/openapi/v3.yaml post /addresses/validate-destination
Permissions required: **None**
Validate that a given address for a given networkId is valid as a transfer destination.
Returns 200 if the address is valid, or an invalid request error if it is not.
# List Asset Types
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v3/asset-types-&-networks/list-asset-types
/knowledge-base/openapi/v3.yaml get /asset-types
Permissions required: **None**
List all supported asset types for your organization.
# List Networks
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v3/asset-types-&-networks/list-networks
/knowledge-base/openapi/v3.yaml get /networks
Permissions required: **None**
List all blockchain networks supported by your organization.
# Get a counterparty by ID
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v3/atlas-settlement-network/get-a-counterparty-by-id
/knowledge-base/openapi/v3.yaml get /atlas/directory/counterparties/{counterpartyId}
Permissions required: **Read vault activity**
Get a single trusted counterparty by its ID.
# Get a participant by ID
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v3/atlas-settlement-network/get-a-participant-by-id
/knowledge-base/openapi/v3.yaml get /atlas/directory/participants/{participantId}
Permissions required: **Read vault activity**
Get a single participant by its ID.
# List participants
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v3/atlas-settlement-network/list-participants
/knowledge-base/openapi/v3.yaml get /atlas/directory/participants
Permissions required: **Read vault activity**
Get the list of participants you have access to.
# List trusted counterparties
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v3/atlas-settlement-network/list-trusted-counterparties
/knowledge-base/openapi/v3.yaml get /atlas/directory/counterparties
Permissions required: **Read vault activity**
Get trusted counterparties.
# Propose a trusted counterparty
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v3/atlas-settlement-network/propose-a-trusted-counterparty
/knowledge-base/openapi/v3.yaml post /atlas/directory/counterparties
Permissions required: **Propose Trusted Counterparty**
Propose adding a new trusted counterparty for a participant.
# Get Staking Position Balances
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v3/balances/get-staking-position-balances
/knowledge-base/openapi/v3.yaml get /wallets/{walletId}/staking-positions/{positionId}/balances
Permissions required: **Read vault activity**
Get current balances for a specific staking position (e.g., validator, stake account).
# Get Wallet Balances
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v3/balances/get-wallet-balances
/knowledge-base/openapi/v3.yaml get /wallets/{walletId}/balances
Permissions required: **Read vault activity**
Get current balances for a specific wallet. Returns all balance types including wallet-level balances and aggregated staking position balances.
# Get Wallet Staking Positions
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v3/balances/get-wallet-staking-positions
/knowledge-base/openapi/v3.yaml get /wallets/{walletId}/staking-positions
Permissions required: **Read vault activity**
Get staking positions for a specific wallet.
# API Reference
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v3/introduction
Generated reference for the Anchorage Digital REST API v3.0.
## Authentication
All API requests require the `Api-Access-Key` header.
```http theme={null}
Api-Access-Key: YOUR_ACCESS_KEY
```
Some endpoints also require:
```http theme={null}
Api-Timestamp: 1577880000
Api-Signature: 4bf42054bf7db1f8...
```
Read [Authentication](https://docs.anchorage.com/porto/developers/setting-up) and [Request signing](https://docs.anchorage.com/porto/developers/request-signing)
before sending signed requests.
## Endpoint areas
Propose, accept, authorize, and list Atlas settlements.
Transfer fiat via wire, ACH, or book. Setup virtual accounts for your organization.
Read balances, wallet activity, supported assets, and vault information.
## Production server
```text theme={null}
https://api.anchorage.com/v3
```
# Propose Raw Transaction
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v3/transaction-creation/propose-raw-transaction
/knowledge-base/openapi/v3.yaml post /wallet-operations/create/propose-raw-transaction
Permissions required: **Propose create transaction**
Propose an off-chain signature or on-chain execution raw transaction for approval workflow.
This endpoint creates a raw transaction but defers signing. The operation stays in PENDING status
and requires approval through your organization's workflow before signing occurs.
Supported raw transaction types include Ethereum structured data signing (EIP-712), Ethereum personal message
signing, Ethereum transaction execution, and Solana raw transaction execution.
This endpoint returns immediately with a `walletOperationId` in `PENDING` status. The transaction
will not be signed until it receives the required endorsements through your approval workflow. Poll
`GET /wallet-operations/{walletOperationId}` to check the status.
An operation awaiting approval and an operation being signed both read as `PENDING`. An operation that is
rejected by an approver, rejected during Anchorage Digital review, or that expires without approval moves to
`FAILED`. Poll with a timeout rather than indefinitely.
# Get Wallet Operation
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v3/wallet-operations/get-wallet-operation
/knowledge-base/openapi/v3.yaml get /wallet-operations/{walletOperationId}
Permissions required: **Read vault activity**
Get details of a specific wallet operation by ID.
Wallet operations represent transactions that your organization signed, such as transfers and
staking operations. For an operation you created through the v3 endpoints, COMPLETED means the
transaction was signed and returned to you. These endpoints do not broadcast, so it reaches the
network only once you broadcast it. expectedTransactionHash, when present, is predicted before
broadcast and may differ from the final hash.
# List Wallet Operations
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v3/wallet-operations/list-wallet-operations
/knowledge-base/openapi/v3.yaml get /wallet-operations
Permissions required: **Read vault activity**
List wallet operations with optional filtering.
Wallet operations represent transactions that your organization signed. This includes transfers,
staking operations, and other specialized transactions.
For an operation you created through the v3 endpoints, COMPLETED means the transaction was signed
and returned to you. These endpoints do not broadcast, so it reaches the network only once you
broadcast it. expectedTransactionHash, when present, is predicted before broadcast and may differ
from the final hash.
# Get Daily Wallet Rewards (Aggregated)
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v3/wallets/get-daily-wallet-rewards-aggregated
/knowledge-base/openapi/v3.yaml get /wallets/{walletId}/daily-rewards
Permissions required: **Read vault activity**
Get daily aggregated rewards for a wallet over a specified date range (maximum 31 days).
# Get Wallet
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v3/wallets/get-wallet
/knowledge-base/openapi/v3.yaml get /wallets/{walletId}
Permissions required: **Read vault activity**
Retrieve a wallet by ID. Use this endpoint to poll for wallet creation status after calling POST /wallets.
# Get Wallet Rewards (Per-Event)
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v3/wallets/get-wallet-rewards-per-event
/knowledge-base/openapi/v3.yaml get /wallets/{walletId}/rewards
Permissions required: **Read vault activity**
Get individual reward events for a wallet over a specified date range.
# List Wallets
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v3/wallets/list-wallets
/knowledge-base/openapi/v3.yaml get /wallets
Permissions required: **Read vault activity**
List all wallets in the organization.
# Webhooks
Source: https://docs.anchorage.com/knowledge-base/porto/api-reference/v3/webhooks
Receive event-driven notifications for operations and transactions across crypto and USD.
Anchorage Digital webhooks enable you to receive event-driven notifications for operations and transactions across both crypto and USD. Event notifications are configurable by endpoint and by event type.
## Transaction lifecycle
```mermaid theme={null}
stateDiagram-v2
[*] --> approved
approved --> canceled: canceled webhook
approved --> processing: begin processing event
processing --> sent: finish processing event
sent --> failed: failed webhook
sent --> complete: completed webhook
complete --> returned: returned webhook
complete --> [*]
canceled --> [*]
failed --> [*]
returned --> [*]
classDef terminal fill:#f96,stroke:#333,stroke-width:3px
class canceled,failed,complete,returned terminal
```
## Supported events
### Outgoing wire
| Event ID | Name | Payload fields | Description |
| :------------------------------------------- | :----------------- | :------------------------------------------ | :------------------------------------------------------------------------------------------------------ |
| `fiat-banks-outbound-wire.cancelled` | cancelled | `id, status, event_time, live_mode` | Canceled outbound wire. Only occurs if Anchorage Digital cancels before processing begins. |
| `fiat-banks-outbound-wire.begin_processing` | begin\_processing | `id, status, event_time, live_mode` | Bank has begun processing. Payment cannot be canceled after this point. Status moves to `processing`. |
| `fiat-banks-outbound-wire.finish_processing` | finish\_processing | `id, status, event_time, live_mode` | Bank has finished processing. Status moves to `sent`. |
| `fiat-banks-outbound-wire.failed` | failed | `id, status, reason, event_time, live_mode` | Payment failed at the bank or network level (e.g., misconfigured receiving account or blocked account). |
| `fiat-banks-outbound-wire.completed` | completed | `id, status, event_time, live_mode` | Payment settled. Originating and receiving accounts reflect balance changes. |
| `fiat-banks-outbound-wire.returned` | returned | `id, status, reason, event_time, live_mode` | Wire returned. Return codes are not populated for wires. |
### ACH debit/credit
| Event ID | Name | Payload fields | Description |
| :------------------------------------------ | :----------------- | :------------------------------------------------ | :---------------------------------------------------------------------------------------------------- |
| `fiat-banks-outbound-ach.cancelled` | cancelled | `id, status, event_time, live_mode` | Canceled outbound ACH. Only occurs if Anchorage Digital cancels before processing begins. |
| `fiat-banks-outbound-ach.begin_processing` | begin\_processing | `id, status, event_time, live_mode` | Bank has begun processing. Payment cannot be canceled after this point. Status moves to `processing`. |
| `fiat-banks-outbound-ach.finish_processing` | finish\_processing | `id, status, event_time, live_mode` | Bank has finished processing. Status moves to `sent`. |
| `fiat-banks-outbound-ach.completed` | completed | `id, status, event_time, live_mode` | Payment settled. Originating and receiving accounts reflect balance changes. |
| `fiat-banks-outbound-ach.returned` | returned | `id, status, reason, code, event_time, live_mode` | ACH returned. |
### Notice of change
| Event ID | Name | Payload fields | Description |
| :------------------------------------- | :------- | :------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `fiat-banks-notice-of-change.received` | received | `payment_id, code, reason, originating_account_id, event_time, live_mode, corrections` | Notice of change received for a payment. The `corrections` field contains tag/value corrections that must be applied to the originating account for future payments. |
### Book transfer
| Event ID | Name | Payload fields | Description |
| :------------------------------------------- | :----------------- | :---------------------------------- | :---------------------------------------------------------------------------------------------------- |
| `fiat-banks-outbound-book.cancelled` | cancelled | `id, status, event_time, live_mode` | Canceled outbound book transfer. Only occurs if Anchorage Digital cancels before processing begins. |
| `fiat-banks-outbound-book.begin_processing` | begin\_processing | `id, status, event_time, live_mode` | Bank has begun processing. Payment cannot be canceled after this point. Status moves to `processing`. |
| `fiat-banks-outbound-book.finish_processing` | finish\_processing | `id, status, event_time, live_mode` | Bank has finished processing. Status moves to `sent`. |
| `fiat-banks-outbound-book.completed` | completed | `id, status, event_time, live_mode` | Transfer settled. Originating and receiving accounts reflect balance changes. |
### Incoming wire
| Event ID | Name | Payload fields | Description |
| :---------------------------------- | :-------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------ |
| `fiat-banks-inbound-wire.completed` | completed | `id, type, amount, posted, live_mode, vendor_id, as_of_date, as_of_time, created_at, reconciled, updated_at, vendor_code, vendor_code_type, vendor_description, internal_account_id, event_time, sender_name, sender_account_number, sender_routing_number, sender_bank` | Inbound wire settled. Terminal state. |
### Interest payment
| Event ID | Name | Payload fields | Description |
| :------------------------------ | :-------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------- |
| `fiat-banks-interest.completed` | completed | `id, type, amount, posted, live_mode, vendor_id, as_of_date, as_of_time, created_at, reconciled, updated_at, vendor_code, vendor_code_type, vendor_description, internal_account_id, event_time` | Interest payment received. Terminal state. No sender information — payment originated at the bank. |
# Activity & transaction history
Source: https://docs.anchorage.com/knowledge-base/porto/assets/activity-history
View and track all operations and transactions across your vaults.
You're viewing **Porto** documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/users/overview)
Activity shows a complete audit trail of every operation in your vaults—from deposits and withdrawals to policy changes and user management. Use activity to track status, verify transactions, and maintain compliance records.
## View activity
From the home screen, tap the **Activity** icon (looks like a timeline or history icon).
Activity displays recent operations in reverse chronological order (newest first).
Select any transaction to see full details, including status, approvals, and blockchain information.
## Activity types
Activity includes all operations:
* **Deposits** — Assets received into your vaults
* **Withdrawals** — Assets sent from your vaults
* **Transfers** — Movements between your vaults or to trusted partners
* **Swaps** — Asset exchanges (if stablecoin conversion is enabled)
* **User management** — Users added, removed, or had permissions changed
* **Policy changes** — Updates to admin policies, quorum rules, or vault policies
* **Settings changes** — Changes to organization settings or vault configurations
* **Approvals** — Operations approved or rejected
## Transaction status
Each transaction shows its current status:
| Status | Meaning |
| :--------------------------- | :----------------------------------------------- |
| **Pending initiation** | Awaiting the initiator's biometric approval |
| **Pending approval** | Initiated, awaiting quorum approval |
| **Pending Anchorage review** | Awaiting Anchorage Digital compliance review |
| **Approved** | All approvals complete, ready to broadcast |
| **Broadcasting** | Being submitted to the blockchain |
| **On-chain pending** | Submitted to blockchain, awaiting confirmation |
| **Confirmed** | Blockchain confirmed the transaction |
| **Failed** | Transaction was rejected or failed at some stage |
## Transaction details
When you tap a transaction, you'll see:
* **Basic info** — Type (deposit, withdrawal, etc.), amount, asset, timestamp
* **Parties involved** — Who initiated and who approved
* **Approvals** — List of approvers and their sign-off times
* **Blockchain info** — Transaction hash (if on-chain), network, confirmation count
* **Comments** — Any notes added during initiation
* **History** — Timeline of when the transaction entered each status
## Filter and search
Use the filters in activity to find specific transactions:
* **Asset type** — Show only transactions for a specific asset
* **Type** — Filter by operation type (deposits, withdrawals, policy changes, etc.)
* **Date range** — Show transactions within a specific time period
* **Status** — View only pending, completed, or failed operations
* **Vault** — View activity for a specific vault
The **Vault** filter narrows what's displayed, not what's visible. Today, any user added to the organization can see activity across all vaults, regardless of role — Operator, Viewer, or Admin. Vault-level visibility gating, so users only see activity for the vaults they're assigned to, is coming soon.
## Pending approvals
Transactions awaiting approval show a **Pending approval** badge. To see what needs approval:
Pending items appear at the top of activity with a **Pending** badge.
View who still needs to approve and when it expires.
If you're a designated approver, you can approve directly in the activity view (if your role permits).
If approvals are delayed, contact your organization's approvers directly.
Pending approvals typically expire after 24 hours if not completed. Once expired, the operation must be resubmitted.
## Failed or stuck transactions
If a transaction failed or is stuck:
1. **Check the status** — Tap the transaction to see where it failed
2. **Common reasons for failure**:
* Insufficient balance or gas fees
* Policy rejection by compliance team
* Blockchain network congestion (on-chain pending)
* Approval timeout (older than 24 hours)
3. **Retry options** — Depending on the failure reason, you may be able to resubmit or contact support
## Export activity
To download your activity for accounting or compliance purposes:
Tap the filter icon to narrow down what you want to export.
Tap **Export** or **Download** (availability depends on your permissions).
Select CSV or PDF format.
The file will download and be saved locally.
Export may require admin approval or specific permissions. Contact your administrator if you don't see the export option.
## Activity and compliance
Your activity log serves as an audit trail for:
* **Regulatory reporting** — Compliance with AML/KYC requirements
* **Internal audits** — Verifying who initiated each operation and when
* **Tax reporting** — Tracking cost basis and transaction dates
* **Dispute resolution** — Proving when transactions were initiated and approved
Preserve your activity records for regulatory compliance periods.
# Adding multiple destinations
Source: https://docs.anchorage.com/knowledge-base/porto/assets/adding-multiple-destinations
Set up and manage multiple trusted destinations for efficient withdrawals.
You're viewing **Porto** documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/users/overview)
If you regularly withdraw to many addresses, you can add multiple [trusted destinations](/knowledge-base/porto/assets/trusted-destinations) to streamline the process. Porto lets you organize and manage a large set of pre-approved addresses efficiently.
## Why use multiple destinations
Multiple trusted destinations are useful for:
* **Regular vendors** — Different addresses for different service providers
* **Client wallets** — Multiple addresses for different clients if you're managing custody
* **Segregated accounts** — Different addresses for different business purposes
* **Exchange accounts** — Multiple exchange withdrawal addresses
* **Geographic separation** — Addresses in different regions or custodians
## Add multiple destinations in bulk
From the home screen, go to **Settings** > **Trusted destinations**.
Look for **Add multiple**, **Bulk import**, or **Import addresses**. Some versions allow importing a list instead of adding one by one.
Create a list with the following information for each address:
* Wallet address
* Asset type (Bitcoin, Ethereum, etc.)
* Label/name
* Description (optional)
If bulk import is supported:
* Copy/paste a CSV or comma-separated list
* Upload a file with address data
If not, add them individually using the standard [Add a trusted destination](/knowledge-base/porto/assets/trusted-destinations) flow.
Carefully verify each address — you cannot edit them after creation, and wrong addresses cannot be recovered.
Submit the batch for approval. Depending on your policies, each destination or the entire batch may require approval.
Approvers will review the full list of destinations you're adding and approve them.
Wallets address verification is critical when adding multiple destinations. Verify each address character-by-character:
* A single typo makes an address unusable
* Assets sent to the wrong address cannot be recovered
* When adding in bulk, the risk of errors increases
Consider:
* Adding a few at a time instead of all at once
* Having a colleague verify the list independently
* Starting with a small test transfer before full use
## Organize destinations with labels
When adding multiple destinations, use clear, consistent naming:
| Good label | Avoid |
| :--------------------------- | :--------- |
| "Acme Inc Settlement Wallet" | "acme" |
| "Exchange X Hot Wallet" | "exchange" |
| "Treasury Reserve Bitcoin" | "BTC" |
| "Client A - USDC Wallet" | "A" |
Clear labels make it easier to find the right destination when you have many addresses.
## View all destinations
From **Settings**, tap **Trusted destinations**.
You'll see all trusted destinations organized by asset type or label.
Use filters to find addresses:
* By asset type (Bitcoin, Ethereum, etc.)
* By label or organization
* By date added
Tap any destination to see:
* Full address
* Asset type
* When it was added
* Who added it
* Transfer history
## Use multiple destinations in withdrawals
When you've set up multiple destinations:
From the home screen, select the vault and asset you want to withdraw.
Select **Send** or **Withdraw**.
Tap **Trusted destination** or **Select from saved addresses**.
Find the address you want from your list by:
* Scrolling through the list
* Searching by label or organization
* Filtering by asset type
Verify the name matches your intent. The label will appear instead of the full address.
Follow the standard withdrawal flow to complete the transaction.
## Remove a destination
To remove a trusted destination:
1. **Go to Settings** — Tap **Settings** > **Trusted destinations**
2. **Select the destination** — Tap the address you want to remove
3. **Request removal** — Select **Remove** or **Delete**. Only administrators can remove destinations in most organizations
4. **Await approval** — The removal request may require approval
See [Trusted destinations - Remove](/knowledge-base/porto/assets/trusted-destinations) for full details.
## Batch withdrawals to multiple destinations
If you need to send assets to several destinations, you have two options:
1. **Submit individually** — Initiate separate withdrawals to each destination (full approval flow for each)
2. **Batch endorsement** — Group multiple withdrawals for combined approval (faster)
See [Batch endorsements](/knowledge-base/porto/policies/batch-endorsements) for details on batching multiple withdrawals.
## Best practices for managing many destinations
* **Organize by purpose** — Group destinations by business purpose (settlements, clients, reserves) using clear labels
* **Use descriptions** — Add notes about why each destination exists
* **Regular audits** — Periodically review your destinations to ensure they're still active and valid
* **Mark inactive destinations** — Some organizations let you mark destinations as inactive instead of deleting them
* **Document external** — Keep external records of major destinations for compliance and audit purposes
* **Verify before withdrawal** — Always double-check the destination label before initiating a withdrawal
## Importing existing addresses
If you have addresses from another system or custody provider:
1. **Export the list** — Get addresses from your previous system in a format (CSV, spreadsheet, etc.)
2. **Standardize** — Ensure all addresses are valid and properly formatted for the asset type
3. **Add descriptive labels** — Include clear labels for each address indicating its purpose
4. **Import to Porto** — Use the bulk import feature or add individually
5. **Verify in Porto** — Confirm all addresses appear correctly and are ready for use
# Deposits
Source: https://docs.anchorage.com/knowledge-base/porto/assets/deposits
Receive digital assets into your vaults and track deposit status.
You're viewing **Porto** documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/users/overview)
Deposits bring digital assets from external sources into your Porto vaults. You can receive deposits from exchanges, other custodians, individuals, or any external wallet.
## Share a deposit address
To receive assets, share your vault's wallet address with the sender.
From the home screen, select the vault you want to receive assets into.
Tap the asset type you want to receive (e.g., Bitcoin, Ethereum).
You'll see all wallet addresses for that asset in the vault. Each wallet has a unique address.
Tap the address or the share icon to copy it. Send this address to the sender.
If you're receiving from a regular source, ask the sender to save your address as a trusted destination on their system for future transfers.
Each wallet address is unique to that wallet. Using the same address multiple times is safe and recommended for tracking purposes.
## Receive from a trusted source
If the sender has saved your address as a trusted destination, they can send assets directly without additional verification delays.
For senders using Porto or Anchorage Digital custody accounts, transfers between [trusted destinations](/knowledge-base/porto/assets/trusted-destinations) are streamlined and require minimal approval time.
## Track incoming deposits
### In activity
All incoming deposits appear in your activity history with:
* **Asset type** — The asset being deposited
* **Amount** — How much was sent
* **Sender address** — Where the assets came from
* **Status** — Processing, confirmed, or failed
* **Timestamp** — When the deposit was initiated
### Confirmation times
Deposit confirmation depends on the blockchain:
* **Fast blockchains** (Solana, Polygon) — Minutes to confirm
* **Standard blockchains** (Ethereum, Bitcoin mainnet) — 10-60 minutes
* **Testnet assets** — Variable, used for testing only
## Deposit failed or delayed
If a deposit hasn't appeared:
1. **Check the blockchain** — Verify the sender sent to the correct address and the transaction was initiated
2. **Review activity** — Look for the transaction in your [activity history](/knowledge-base/porto/assets/activity-history) to see status
3. **Contact the sender** — Confirm they sent the correct amount to the correct address
4. **Request asset support** — If the deposit was sent but hasn't arrived after reasonable confirmation time, contact your account team
Triple-check wallet addresses before giving them to senders. Sending assets to the wrong address cannot be reversed. If you're unsure about an address, contact your account team to verify.
## Receive in multiple wallets
Your vault can have multiple wallets for the same asset. This is useful for:
* **Segregating funds** — Keep different deposit sources separate
* **Sharing addresses** — Give different senders different addresses for tracking
* **Risk management** — If one wallet is compromised, others remain unaffected
To receive in a different wallet, select a different wallet address in the asset view.
# Receiving assets
Source: https://docs.anchorage.com/knowledge-base/porto/assets/receiving-assets
Deposit assets into Porto vaults and request support for new assets.
You're viewing **Porto** documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/users/overview)
## Creating a deposit address
To receive a deposit, you need a deposit address for that asset. Creating a deposit address generates a new wallet and prompts you to download the encrypted wallet key. An encrypted wallet key can be decrypted and exported if you choose to import the wallet into another service provider.
The encrypted wallet key is NOT sensitive unless decrypted. Only administrators can decrypt the wallet key to import it into another wallet service provider.
### Getting a deposit address (iOS)
Go to the desired vault and tap **Deposit**, then select the asset.
Tap **Download wallet key** (or tap **Why does this matter** to learn more). Choose your save method—for example, tap **Save to files**. If you already have wallet keys downloaded, select **Keep both** and rename them.
After saving your wallet keys and tapping **Continue**, select the wallet to view its address. Copy or share the deposit address or QR code with the sending party.
### Getting a deposit address (web dashboard)
Go to the desired vault in the web dashboard and select the asset.
Select an existing wallet or create a new one.
Copy and share the address with the sending party.
Vault members receive a notification every time a deposit is made to the vault.
## Requesting new asset support
Porto supports hundreds of assets, including all ERC-20 and SPL tokens—even those not explicitly listed in the app.
In the iOS app, go to **Settings** and tap **Supported assets**. Search for the asset by name or symbol.
If the asset is not yet supported, tap to submit an asset support request.
You can self-custody all ERC-20 and SPL assets, including assets not shown in the app. For faster processing, include the token's contract address in your request.
For further questions, contact [portohelp@anchorage.com](mailto:portohelp@anchorage.com).
## Finding an ERC-20 token contract address
Block explorers let you view and search the blockchain for transactions, addresses, tokens, and other activity. Having a token's contract address allows you to add the token directly on Porto by pasting the address into the Asset Support Request form.
* Aptos: [explorer.aptoslabs.com](https://explorer.aptoslabs.com/?network=mainnet)
* Arbitrum: [arbiscan.io](https://arbiscan.io/)
* Base: [basescan.org](https://basescan.org/)
* Ethereum: [etherscan.io](https://etherscan.io/)
* Optimism: [optimistic.etherscan.io](https://optimistic.etherscan.io/)
* Plume: [explorer.plumenetwork.xyz](https://explorer.plumenetwork.xyz/)
* Polygon: [polygonscan.com](https://polygonscan.com/)
* Solana: [solscan.io](https://solscan.io/)
* ZKSync: [explorer.zksync.io](https://explorer.zksync.io/)
Search for the token using its name or symbol.
The contract address will be clearly indicated on the token's page. Copy it for use in the Porto Asset Support Request form.
# Sending assets
Source: https://docs.anchorage.com/knowledge-base/porto/assets/sending-assets
Withdraw assets, use DApps, manage trusted destinations, and batch endorsements.
You're viewing **Porto** documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/users/overview)
## Withdrawals
Withdrawals fall under vault policies. Both administrators and vault members who have been added to a vault can initiate and approve withdrawals.
You may initiate withdrawals in the iOS app or on the web dashboard. If initiated from the web dashboard, biometric approval must be submitted in the iOS app.
### Withdrawing from iOS
Go to the desired vault and tap **Withdraw**.
Search for and tap the asset you would like to withdraw, then select the wallet from which you would like to withdraw.
Enter the withdrawal amount and tap **Continue**. Enter the destination address, scan it, or choose one of your trusted destinations or vaults.
Add a comment (optional), review the withdrawal details, and tap **Submit for approval**. Vault members and administrators will receive a notification to approve the withdrawal via quorum.
### Withdrawing from the web dashboard
Go to the desired vault in the web dashboard.
Select the asset and wallet from which you would like to withdraw, then enter the amount.
Enter the destination address to which you would like to send the funds.
Review and confirm the information, then submit. Open the iOS app to endorse the withdrawal with biometric approval.
### Quorum approvals
Members of the vault policy will receive a notification to approve the withdrawal. Once the required quorum approvals are submitted, Porto will process the withdrawal.
## Using decentralized apps
You can connect to any decentralized application (dApp) that supports WalletConnect on supported networks. WalletConnect is currently supported on Ethereum, Arbitrum, ZKsync, Base, Optimism, Avalanche C-Chain, and Polygon. You can sign any smart contract interaction using your Porto wallet on these networks.
Only trusted dApps and smart contracts should be used. To request support for additional networks, contact [portohelp@anchorage.com](mailto:portohelp@anchorage.com).
### Connecting via WalletConnect (iOS)
Tap the QR code scanner icon in the top right corner of the home page.
Open the dApp and initiate a WalletConnect connection. Scan the QR code displayed by the dApp.
Select the wallet you want to connect and tap **Connect**. On-chain token balances will be available within the dApp once connected.
### Interacting with smart contracts
Navigate to the dApp, select an operation (for example, swap), and tap **Confirm**.
The initiator will receive an approval request in the notifications tab. Tap the bell icon, then tap **Approve** and submit biometric authentication.
Once approved by the initiator, quorum approvers approve or reject the transaction and submit biometric authentication. After the policy quorum is met, the transaction is sent to the HSM for verification and signing.
Once the transaction is broadcast and confirmed, the on-chain interaction will complete within approximately five minutes.
## Trusted destinations
Administrators may add trusted destinations to ease and speed up the withdrawal process. Trusted destinations can be shared across assets on the same network.
### Adding a trusted destination
Go to **Settings** and tap **Trusted destinations**, then tap **Add trusted destination**.
Search for and select the asset associated with the destination.
Scan or paste the address, then enter a name and description. To use the same trusted destination across assets on the same network, select the checkbox under **Description**.
Review the operation details and submit for quorum approval.
### Adding trusted destinations in bulk (CSV)
Administrators can import multiple trusted destinations at once using a CSV file from the web dashboard. Contact [portohelp@anchorage.com](mailto:portohelp@anchorage.com) for the CSV template and instructions.
### Removing a trusted destination
Only administrators can remove trusted destinations. Removal requires quorum approval.
Go to **Settings** and tap **Trusted destinations**.
Tap the trusted destination to be removed, then tap **Remove**.
Add a comment (optional), tap **Review** to review the details, and submit for quorum approval.
## Batch endorsements
Multiple operations can be approved simultaneously in the Porto iOS app, allowing for secure and efficient approval of pending activity.
Go to **Pending activity** (bell icon) to see the list of operations awaiting approval.
Tap **Select** in the top right corner. Select the operations you wish to approve and tap **Confirm and review**.
Review each operation's details and select **Approve**, **Reject**, or **Review later** as appropriate.
Once finished, review the selection for each operation and follow the prompts to submit biometric approval.
Batched endorsements are processed once the required quorum is met.
# Stablecoins
Source: https://docs.anchorage.com/knowledge-base/porto/assets/stablecoins
Earn stablecoin rewards in Porto.
Porto by Anchorage Digital lets you earn stablecoin rewards on eligible stablecoins held in self-custody. Your assets remain accessible at any time — no lending, no rehypothecation, and no lockups.
For eligibility requirements, enrollment steps, and current reward rates, see the [Anchorage Digital platform's stablecoins page](https://docs.anchorage.com/knowledge-base/platform/users/stablecoins#stablecoin-rewards), which is maintained as the source of truth for this program.
# Swaps
Source: https://docs.anchorage.com/knowledge-base/porto/assets/swaps
Swap assets directly within Porto.
You're viewing **Porto** documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/users/overview)
## Swapping on Porto
Swap tokens directly on Porto by Anchorage Digital, powered by the Uniswap protocol. Swapping is trading one token for another within the same blockchain.
### How to swap tokens (web dashboard)
In Porto, go to the **Swap** page from the left navigation.
Select your **Sell** token from the modal. The modal displays all tokens grouped within wallets of your organization.
Select your **Buy** token. The buy token list is pre-filtered by the network of your sell token.
Input a sell or buy amount to generate a quote. Review the quote details including fees, price impact, slippage, and route.
The quote refreshes every 10 seconds.
Click **Swap** to initiate. Swaps must be signed within 30 minutes of initiating the transaction.
### Setting a token allowance
When initiating a token swap for the first time from a wallet, you will be prompted to set a token allowance:
Allows Permit2 to access your entire token balance for future swaps without requiring further allowance approvals.
Allows Permit2 to access only the swap amount. Future swaps will require a new token allowance to be approved.
### Tracking recent transactions
Track your recent swap activity via the **Recent transactions** widget on the right side of the Swap page. Transactions are sorted by initiated date and time, with the most recent at the top.
Expand each transaction to see the status and next steps. Each step corresponds to an operation—click **Details** to view the full operation details. All transactions initiated within the last 48 hours are displayed in this list.
## Swap concepts
Swaps require gas fees, like other blockchain transactions. All applicable fees are displayed in the quote before you execute the swap.
The maximum price change allowed before your transaction automatically fails, protecting you from unexpected price movements.
How the trade will affect the market price of assets in the liquidity pool.
The path the trade will take, automatically calculated to find the best price based on your preferences.
# Trusted counterparties
Source: https://docs.anchorage.com/knowledge-base/porto/assets/trusted-counterparties
Manage trusted organizations and relationships for regular transfers.
You're viewing **Porto** documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/users/overview)
Trusted counterparties are organizations or external partners you have regular transfers with. By designating them as trusted, you can streamline approval workflows and simplify recurring transactions. This feature is available for organizations that have enabled counterparty management.
Trusted counterparties is a feature for organizations with recurring transfer relationships. Ask your administrator if this is enabled for your organization.
## What is a trusted counterparty
A trusted counterparty is:
* **An organization or relationship** — Unlike [trusted destinations](/knowledge-base/porto/assets/trusted-destinations) which are individual wallet addresses, counterparties represent entire organizations
* **Pre-approved for transfers** — You can transfer assets to their approved wallet addresses with streamlined approvals
* **Reduced friction** — Transfers to trusted counterparties may require fewer approvals
* **Auditable relationship** — Your organization keeps a record of all transfers to trusted counterparties
## Add a trusted counterparty
From the home screen, tap the **Settings** icon.
Look for **Trusted counterparties**, **Partners**, or **External organizations** in settings.
Select **Add counterparty** or the **+** button.
Provide:
* **Organization name** — Name of the external organization (e.g., "Exchange Settlement Account")
* **Description** — Notes about the relationship (e.g., "Daily settlements with X exchange")
* **Administrator contact** — Email or contact info for their account administrator
List all wallet addresses this counterparty will receive transfers at. Include:
* **Address** — The wallet address (verify carefully)
* **Asset type** — Which asset this address receives (Bitcoin, Ethereum, etc.)
* **Label** — A name for this address (e.g., "Settlement wallet")
Configure how transfers to this counterparty are approved:
* **Standard approval** — Use vault policies
* **Fast approval** — Reduced approval requirements for trusted counterparties
* **Single approver** — Only one approver needed instead of quorum
Tap **Submit**. Adding a trusted counterparty requires approval based on your policies.
If you have approval permissions, complete biometric authentication to authorize adding this counterparty.
Adding a trusted counterparty reduces approval friction, which can speed up transfers but also increases risk. Only add counterparties you have verified and trust completely.
## View trusted counterparties
From the home screen, tap **Settings**.
Go to **Trusted counterparties** to see all organizations you've designated as trusted.
Tap a counterparty to see:
* Organization name and description
* All associated wallet addresses
* Approval requirements
* Transfer history
## Transfer to a trusted counterparty
Open a vault, select an asset, and tap **Send** or **Withdraw**.
Look for a **Select counterparty** or **Trusted organizations** option.
Choose the organization you want to transfer to.
Choose which address of theirs to send to (if they have multiple).
Type the amount you want to transfer. The app will show fees and confirm your balance.
Verify the counterparty name, address, and amount are correct.
Complete biometric authentication. If fast approval is enabled, the transfer may complete quickly.
## Edit a trusted counterparty
Tap **Settings** > **Trusted counterparties**.
Tap the organization you want to edit.
Select **Edit** or the pencil icon.
You can update:
* Description and contact information
* Wallet addresses (add new ones or mark old ones as inactive)
* Approval requirements
Changes to trusted counterparties require approval.
## Remove a trusted counterparty
Removing a trusted counterparty prevents future transfers to them. Historical transfers remain in your audit trail.
Tap **Settings** > **Trusted counterparties**.
Tap the organization you want to remove.
Select **Remove counterparty** or **Delete**.
You'll be asked to confirm you want to remove this counterparty.
Depending on your policies, removal may require approval.
Removing a counterparty doesn't affect historical transfers. All past transactions with them remain in your Activity log.
## Counterparties vs. destinations
| Feature | Trusted counterparties | Trusted destinations |
| :------------- | :-------------------------------------------- | :------------------------------------ |
| **Scope** | Organizations or relationships | Individual wallet addresses |
| **Use case** | Recurring transfers to the same organization | Single one-time or frequent addresses |
| **Approval** | Can customize approval rules per counterparty | Uses vault policies |
| **Management** | Managed at organization level | Can be personal or organization-wide |
| **Requires** | Admin setup and approval | User permissions |
If you have a single address to use repeatedly, see [Trusted destinations](/knowledge-base/porto/assets/trusted-destinations). If you have an ongoing relationship with an organization with multiple addresses, use [Trusted counterparties](/knowledge-base/porto/assets/trusted-counterparties).
## For administrators
If you're setting up counterparty management for your organization, see your admin dashboard for:
* Configuring counterparty approval requirements
* Setting organization-wide counterparty policies
* Approving new counterparties
* Managing counterparty relationships
# Trusted destinations
Source: https://docs.anchorage.com/knowledge-base/porto/assets/trusted-destinations
Pre-approve wallet addresses for faster and safer withdrawals.
You're viewing **Porto** documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/users/overview)
Trusted destinations are wallet addresses that your organization has pre-approved for withdrawals. Using trusted destinations speeds up the withdrawal process and reduces approval requirements.
## Why use trusted destinations
* **Faster withdrawals** — Pre-approved addresses require fewer approvals
* **Safer transfers** — You can only withdraw to addresses your organization has verified
* **Batch operations** — Use trusted destinations for [batch endorsements](/knowledge-base/porto/policies/batch-endorsements)
* **Audit trail** — Your organization keeps a record of all approved recipient addresses
## Add a trusted destination
From the home screen, tap the **Settings** icon.
Tap **Trusted destinations**, then tap **Add destination**.
Select the asset this address receives (e.g., Bitcoin, Ethereum).
Provide:
* **Address** — The wallet address (verify carefully—cannot be changed)
* **Label/Name** — A descriptive name (e.g., "Exchange Settlement Address" or "Client Wallet")
* **Description** — Optional notes about why this address is trusted
Verify the address is correct. Withdrawals cannot be reversed if you specify a wrong address.
Tap **Submit**. The destination requires approval based on your organization's policies.
If you have approval permissions, complete biometric authentication to authorize adding this destination.
Always verify wallet addresses character-by-character before submitting. Addresses that are incorrect cannot be used or edited, and assets sent to the wrong address cannot be recovered.
## View trusted destinations
From the home screen, tap the **Settings** icon.
Tap **Trusted destinations** to see all addresses your organization has approved.
Tap a destination to see its address, label, description, and who added it.
## Use a trusted destination for withdrawal
When initiating a [withdrawal](/knowledge-base/porto/assets/withdrawals):
Open the asset and tap **Send**.
Tap **Select from trusted destinations** and choose the address.
Verify the correct trusted destination is selected—the name will appear instead of the raw address.
Follow the normal [withdrawal flow](/knowledge-base/porto/assets/withdrawals). Approvals may be faster for trusted destinations.
## Remove a trusted destination
Destinations can only be removed by administrators. To request removal:
1. **Contact your organization's administrator** — Only admins can remove destinations
2. **Provide a reason** — Explain why the destination should be removed
3. **Await approval** — Removal may require policy approval depending on your organization's settings
Removing a destination does not affect historical withdrawals to that address—only future withdrawals.
## Trusted counterparties vs. trusted destinations
* **Trusted destinations** — Specific wallet addresses you withdraw to
* **Trusted counterparties** — Organizations or relationships you have regular transfers with (if enabled)
[Learn more about trusted counterparties](/knowledge-base/porto/assets/trusted-counterparties).
# Using DApps and smart contracts
Source: https://docs.anchorage.com/knowledge-base/porto/assets/using-dapps
Connect your Porto wallet to decentralized applications and smart contracts.
You're viewing **Porto** documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/users/overview)
Porto allows you to connect your vault wallets to decentralized applications (DApps) like DEXes, lending protocols, and other blockchain services. You can then use your assets for trading, staking, lending, and other operations while maintaining the security of your vaults.
## What is a DApp
A DApp (decentralized application) is an application running on a blockchain that you can interact with using your crypto wallet. Examples include:
* **DEX (Decentralized Exchange)** — Uniswap, Curve, SushiSwap
* **Lending protocols** — Aave, Compound, dYdX
* **Staking services** — Lido, Frax, Curve staking
* **Bridges** — Cross-chain bridges for moving assets between blockchains
* **NFT marketplaces** — OpenSea, Blur, other NFT platforms
## Connect Porto to a DApp
Open the DApp website or app in your browser on your mobile device.
Most DApps have a "Connect wallet" or "Select wallet" button. Tap it.
Select the option for connecting a mobile wallet. Common options include:
* **WalletConnect** — Scan a QR code to connect securely
* **Mobile wallet** — Direct connection if Porto is installed
* **Metamask** — If the DApp supports Metamask-like wallets
Porto will prompt you to approve connecting to the DApp. Review the DApp's request carefully.
Complete Face ID or Touch ID to authorize the wallet connection.
Once connected, your wallet address will appear in the DApp. You can now execute transactions.
## Approving transactions
When you execute a transaction on a DApp (like trading or staking):
The DApp will show you:
* Assets you're sending
* Assets you're receiving
* Gas fees or network costs
* Any other transaction details
Porto will prompt you to approve the transaction. Review the details carefully — **you cannot undo transactions once they're on-chain**.
Complete Face ID or Touch ID to authorize the transaction.
The DApp will submit your transaction to the blockchain. You'll see a status indicator while the transaction is processing.
Use the [Activity log](/knowledge-base/porto/assets/activity-history) to track the transaction status and see when it confirms on-chain.
Smart contracts and DApps carry risks. A malicious or buggy smart contract could:
* Drain your wallet unexpectedly
* Execute trades with poor prices
* Lock your assets or make them inaccessible
Only use DApps you trust, and start with small amounts if you're unfamiliar with a service.
## DApp permissions and security
When you connect Porto to a DApp, you're granting it certain permissions:
| Permission | What it allows |
| :----------------------- | :----------------------------------------------------------------------- |
| **Read address** | The DApp can see your wallet address and balance |
| **Send transactions** | The DApp can create transactions you must approve in Porto |
| **Approve ERC20 tokens** | The DApp can be allowed to spend specific tokens (you approve the limit) |
Each time you interact with a DApp, you'll be asked to approve that specific action. Porto never gives blanket access — you approve each transaction individually.
## Disconnect from a DApp
If you want to revoke a DApp's access:
Most DApps have a **Settings** or **Account** menu.
Look for **Connected wallets**, **Wallet permissions**, or **Connected accounts**.
Select your Porto wallet and tap **Disconnect** or **Revoke access**.
The DApp will no longer be able to initiate transactions from your wallet.
## Best practices for DApp safety
* **Start small** — Test a DApp with a small amount first
* **Use testnet** — Many DApps have test versions where you can practice without real money
* **Research the DApp** — Check reviews, audit reports, and community feedback before using
* **Understand the contract** — Read the DApp's documentation to understand what the smart contract does
* **Keep your password safe** — Your Porto password is your master key — never share it, even with DApps
* **Monitor your balance** — Regularly check your wallet balance to spot unauthorized activity
* **Use [trusted destinations](/knowledge-base/porto/assets/trusted-destinations)** — For frequently used DApps, you can set up trusted addresses to speed up transactions
## For advanced users
See [Smart contracts](/knowledge-base/porto/advanced/smart-contracts) for details on interacting with complex smart contracts and understanding contract interactions at a deeper level.
# Withdrawals
Source: https://docs.anchorage.com/knowledge-base/porto/assets/withdrawals
Send digital assets from your vaults to external addresses.
You're viewing **Porto** documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/users/overview)
Withdrawals transfer digital assets from your Porto vaults to external addresses. All withdrawals require approval based on your vault's policies and proceed through a multi-step authorization flow.
## Initiate a withdrawal
From the home screen, select the vault you want to withdraw from.
Tap the asset type you want to send (e.g., Bitcoin, Ethereum).
Select the wallet you want to withdraw from, then tap **Send**.
Provide the recipient's wallet address or select a [trusted destination](/knowledge-base/porto/assets/trusted-destinations) (faster and safer).
Type the amount you want to send. The app shows fees and confirms you have sufficient balance.
Verify the destination address, amount, and fees. Double-check the address—withdrawals cannot be reversed.
Add internal notes about the withdrawal for your records (e.g., "Q3 settlement with vendor XYZ").
Tap **Continue**. You'll be prompted to complete biometric authentication to initiate the withdrawal.
Complete Face ID or Touch ID to confirm you're authorizing this withdrawal.
## Approval process
After you initiate, the withdrawal moves through approvals:
1. **Your approval** — You've already provided biometric authentication
2. **Quorum approval** — Policy-designated approvers review and authorize (if required)
3. **Anchorage Digital review** — Compliance review of large or unusual withdrawals
4. **Broadcast to blockchain** — Once all approvals are complete, the transaction is sent
5. **On-chain confirmation** — The blockchain confirms the transaction
Withdrawal times depend on your vault's policies and the blockchain. Multi-signature requirements may add 10 minutes to several hours.
## Using trusted destinations
Withdrawals to [trusted destinations](/knowledge-base/porto/assets/trusted-destinations) are faster and safer:
* **Pre-approved** — Addresses are pre-approved by your organization
* **Faster approval** — Reduced approval requirements for frequent recipients
* **Whitelisting** — Only pre-approved addresses can be used for automated or batch withdrawals
[Add a trusted destination](/knowledge-base/porto/assets/trusted-destinations) first, then use it when initiating withdrawals.
## Withdrawal failed or stuck
If your withdrawal hasn't completed:
1. **Check approval status** — View the withdrawal in [activity](/knowledge-base/porto/assets/activity-history) to see if it's pending approval
2. **Request approvals** — If stuck on quorum approval, contact designated approvers in your organization
3. **Check the blockchain** — If broadcasted, search the blockchain explorer for transaction status
4. **Contact support** — If the withdrawal was approved but never broadcast, reach out to your account team
## Withdrawal limits and fees
Withdrawal limits and fee structures are set by your organization's administrator. Check with your account manager for your organization's policies.
## Network fees (gas fees)
When withdrawing, you pay the blockchain network fee for processing your transaction. Network fees vary based on:
* **Blockchain congestion** — During high demand, fees increase
* **Transaction size** — Larger transactions may cost more
* **Gas price** — Set by the blockchain, not by Porto
[Learn more about network fees](/knowledge-base/platform/developers/network-gas-fees).
## Batch withdrawals
If you need to withdraw to multiple destinations, you can:
1. **Submit individually** — Submit each withdrawal separately and manage approvals
2. **Use batch endorsement** — If your organization has batch operations enabled, group withdrawals for combined approval
See [batch endorsements](/knowledge-base/porto/policies/batch-endorsements) for details.
# Atlas network
Source: https://docs.anchorage.com/knowledge-base/porto/atlas
Use Atlas settlement network with Porto.
You're viewing **Porto** documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/users/overview)
Atlas (Anchorage Digital Trusted Liquidity and Settlement) enables seamless transfers between Porto by Anchorage Digital and other Anchorage Digital clients.
## Getting started
Create your network participants to establish your presence on the Atlas network.
Other network participants will use your participant ID to settle with your participants.
Search for counterparties by participant ID and add them to your trusted counterparties list.
## Creating participants
In the web dashboard, select **Settings**, then **Atlas participants**, and select **Create participant**.
Select the account you would like to create a participant for.
Specify the default settlement vault and wallets per network type, then click **Submit**.
Once created, you will see the list of accounts participating in the network along with their corresponding participant IDs. Other counterparties use this ID to find you and initiate a settlement.
## Managing participant details
In the **Participants** tab, click any participant to view its details such as the account name and status. Select **Set or edit** to change the default settlement vault and wallets as applicable.
## Adding trusted counterparties
In the web dashboard, in **Settings**, under **Trusted addresses**, select **Trusted counterparties**, then select **New trusted counterparty**.
Select the participant you would like to add and search for the counterparty by their participant ID.
Add an optional description and select **Submit**. After submitting, quorum approval will be required within the iOS app.
## Reviewing trusted counterparties
Review the status of your trusted counterparties at any time under **Trusted counterparties** in the web dashboard. Select the three dots next to a counterparty to deactivate it if needed.
# Connect your AI assistant
Source: https://docs.anchorage.com/knowledge-base/porto/build-with-ai/connect-ai-assistant
Add the Porto documentation to your AI tools through the hosted MCP server.
You're viewing **Porto** documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/build-with-ai/overview)
Connect our documentation to your AI assistant so it can answer questions and generate integration code grounded in the current docs. Anchorage Digital hosts a Model Context Protocol (MCP) server for this site.
## What the docs MCP server does
The MCP server lets your assistant search these docs and read pages on demand. It's read-only documentation knowledge—it can't access your Porto wallet, keys, or funds, and it can't move assets. To take actions, your integration calls the REST API with your own scoped keys.
| Server | URL | Use for |
| :----------------- | :-------------------------------------- | :------------------------------------------------------------ |
| Public docs | `https://docs.anchorage.com/mcp` | Public documentation |
| Authenticated docs | `https://docs.anchorage.com/authed/mcp` | Documentation restricted to your account, after OAuth sign-in |
## Quick install
The fastest path is the one-line installer, which detects your installed tools:
```bash theme={null}
npx add-mcp https://docs.anchorage.com/mcp
```
You can also open the AI menu at the top of any docs page and choose an install option, such as Cursor, VS Code, or Copy MCP.
## Set up by tool
### Claude Code
```bash theme={null}
claude mcp add --transport http anchorage-docs https://docs.anchorage.com/mcp
```
### Claude Desktop and Claude web
In Settings, select **Connectors**, then select **Add custom connector**.
Enter a name and the URL `https://docs.anchorage.com/mcp`, then save.
### Cursor
Add the server to `mcp.json`:
```json theme={null}
{
"mcpServers": {
"anchorage-docs": {
"url": "https://docs.anchorage.com/mcp"
}
}
}
```
### VS Code (GitHub Copilot)
Add the server to `.vscode/mcp.json`:
```json theme={null}
{
"servers": {
"anchorage-docs": {
"type": "http",
"url": "https://docs.anchorage.com/mcp"
}
}
}
```
### ChatGPT and other clients
In any client that supports custom MCP connectors, add a new connector with the URL `https://docs.anchorage.com/mcp`. To include documentation restricted to your account, use `https://docs.anchorage.com/authed/mcp` and sign in when prompted.
The docs MCP server provides documentation only. It never has access to your API keys or the ability to move assets. See [AI security and guardrails](/knowledge-base/porto/build-with-ai/security).
## Next steps
With your assistant connected, start from a [ready-made prompt](/knowledge-base/porto/build-with-ai/prompts), or review the [security guardrails](/knowledge-base/porto/build-with-ai/security) before you write code that moves assets.
# LLM-ready docs
Source: https://docs.anchorage.com/knowledge-base/porto/build-with-ai/llm-ready-docs
Pull Porto documentation into any AI tool as Markdown.
You're viewing **Porto** documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/build-with-ai/overview)
Every page in these docs is available as clean Markdown that AI tools can read. Use whichever method fits the size of the task—a single page, a product area, or the whole site.
## Copy or open any page
Every page has an AI menu at the top. Use it to copy the page as Markdown, view the raw Markdown, open the page in Claude, ChatGPT, Perplexity, or Google AI Studio, or add the docs to Cursor or VS Code.
## Get a page as Markdown
Append `.md` to any page URL to get its Markdown directly:
```text theme={null}
https://docs.anchorage.com/porto/developers/setting-up.md
```
This is the cleanest way to hand one page to an AI tool or fetch it programmatically.
## Get the whole site
We publish the entire documentation set as a single file for LLM ingestion:
```text theme={null}
https://docs.anchorage.com/llms-full.txt
```
The same file is mirrored at `https://docs.anchorage.com/.well-known/llms-full.txt`.
`llms-full.txt` is large and can exceed an AI tool's context window. For focused work, connect the [MCP server](/knowledge-base/porto/build-with-ai/connect-ai-assistant) or copy only the pages you need.
## Which method to use
| You need | Use |
| :--------------------------------- | :------------------------------------------------------------------------- |
| One page | The AI menu, or append `.md` to the URL |
| A product area, searched on demand | The [MCP server](/knowledge-base/porto/build-with-ai/connect-ai-assistant) |
| The full documentation set | `llms-full.txt` |
# Build with AI
Source: https://docs.anchorage.com/knowledge-base/porto/build-with-ai/overview
Use AI assistants and coding agents to learn and integrate with Porto faster.
You're viewing **Porto** documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/build-with-ai/overview)
You can explore these docs and build your Porto integration with AI assistants and coding agents. Ask questions in natural language, pull our documentation straight into your AI tool, and start from ready-made prompts—while keeping the guardrails that self-custody requires.
## What you can do
Add our docs to Claude, Cursor, VS Code, and more through the hosted MCP server.
Copy any page as Markdown, open it in your AI tool, or pull the whole site.
Start common integrations from copy-paste prompts.
Keep AI agents safe when they touch your self-custodied assets.
## New to AI-assisted development?
An **AI coding assistant**—such as Claude, Cursor, GitHub Copilot, or Windsurf—writes and edits code alongside you. The **Model Context Protocol (MCP)** is an open standard that connects these assistants to outside knowledge and tools, like a universal adapter. The assistant is the **client**; a **server** supplies the knowledge or actions. Anchorage Digital hosts an MCP server for these docs, so your assistant can search and cite them directly instead of guessing.
## Recommended path
Use Claude Code, Cursor, VS Code with Copilot, Windsurf, or the Claude and ChatGPT apps.
Add our MCP server, or pull pages as Markdown, so your assistant answers from the current docs rather than guesswork. See [Connect your AI assistant](/knowledge-base/porto/build-with-ai/connect-ai-assistant).
Use a ready-made prompt for your task. See [Ready-made prompts](/knowledge-base/porto/build-with-ai/prompts).
Use scoped, read-only keys first, and keep a human in the loop before anything moves assets. See [AI security and guardrails](/knowledge-base/porto/build-with-ai/security).
Porto puts you in self-custody of real assets. Before you let an AI agent act on your account, read [AI security and guardrails](/knowledge-base/porto/build-with-ai/security).
## Related
* [Set up API access](/knowledge-base/porto/developers/setting-up) — Create permission groups and keys, and sign requests.
* [API reference](/knowledge-base/porto/api-reference/introduction) — The full REST API, generated from the OpenAPI spec.
# Ready-made prompts
Source: https://docs.anchorage.com/knowledge-base/porto/build-with-ai/prompts
Start common Porto integrations from copy-paste AI prompts.
You're viewing **Porto** documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/build-with-ai/overview)
Copy these prompts into your AI assistant to scaffold common integrations. For the best results, connect the [docs MCP server](/knowledge-base/porto/build-with-ai/connect-ai-assistant) first so the assistant works from the current documentation.
## Integration prompts
You are helping build an integration with the Anchorage Digital REST API (base URL [https://api.anchorage.com/v2](https://api.anchorage.com/v2)). Using the Porto documentation, scaffold a typed API client that authenticates with the `Api-Access-Key` header and signs sensitive requests with an Ed25519 `Api-Signature` and `Api-Timestamp`. Cite the specific documentation pages you rely on, and confirm the current endpoint paths from the docs rather than assuming them.
Using the Porto documentation, outline and implement the steps to withdraw a digital asset: creating a permission group, generating an API key, adding a trusted destination, and submitting the withdrawal. Call out every step that requires quorum approval, and do not bypass human approval. Verify each endpoint against the docs before writing code.
Using the Porto documentation, help me subscribe to and verify webhooks for transfer and deposit events. Show how to validate webhook signatures and how to reconcile each event with the read APIs.
## Keep prompts available in your tool
To reuse guidance across a project, save it in your tool's rules or instructions file:
| Tool | Where to add project instructions |
| :------------- | :---------------------------------------------- |
| Claude Code | `CLAUDE.md` or `AGENTS.md` in your project root |
| Cursor | Project rules in `.cursor/rules` |
| GitHub Copilot | `.github/copilot-instructions.md` |
| Windsurf | Workspace rules in `.windsurf/rules` |
Exact file names change as tools evolve. Confirm the current path in your AI tool's documentation.
## Write your own
Effective prompts share a few habits: point the assistant at our docs or the MCP server, name the exact task, ask it to cite the pages it used, and tell it to verify endpoints and asset types against the docs rather than relying on memory.
Always review AI-generated code before running it, and test thoroughly before production. See [AI security and guardrails](/knowledge-base/porto/build-with-ai/security).
# AI security and guardrails
Source: https://docs.anchorage.com/knowledge-base/porto/build-with-ai/security
Keep AI assistants and agents safe when building on Porto.
You're viewing **Porto** documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/build-with-ai/overview)
AI tools speed up integration, but you're operating on real assets in self-custody. These guardrails keep AI assistants and autonomous agents from causing harm.
## The docs MCP server is read-only
Our documentation MCP server only searches and returns docs. It has no access to your keys, wallet, or funds, and it can't move assets. Connecting it is safe.
## Use least-privilege API keys
Give AI-assisted code only the access it needs. Scope keys with [permission groups](/knowledge-base/porto/developers/permission-groups), and start with read-only keys while you explore. Keep internal and external transfer permissions in separate permission groups and keys.
## Keep a human in the loop for asset movement
Withdrawals and external transfers require quorum approval by design—never let an agent approve them. Treat every asset-moving action as human-approved, not automated. See [quorums](/knowledge-base/porto/policies/quorums) and the [move money overview](/knowledge-base/porto/developers/move-money/overview).
## Protect keys and signing material
Never paste API keys, private keys, or signing secrets into a prompt or chat. Keep them out of your AI tool's context and in your secrets manager. Sensitive endpoints require an Ed25519 signature—generate signatures in your own environment. See [Request signing](/knowledge-base/porto/developers/request-signing).
## Treat AI output as untrusted
* Review generated code before you run it.
* Test thoroughly before production.
* Watch for prompt injection: content an agent fetches from the web can carry hidden instructions, so don't act on it blindly.
* Verify before you sign or broadcast any transaction.
## Verify against current docs
AI models can generate outdated API patterns. Have your assistant cite the documentation pages it used, and confirm endpoint paths and asset types against the current docs or the [MCP server](/knowledge-base/porto/build-with-ai/connect-ai-assistant).
# Changelog
Source: https://docs.anchorage.com/knowledge-base/porto/changelog
Track updates, new features, and improvements to Porto.
You're viewing **Porto** documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/users/overview)
This changelog documents all significant updates to Porto. We update this page regularly as we release new features, improvements, and fixes.
## Recent updates
### Version 2.5.0 (January 2026)
**New Features**
* Stablecoin rewards program integration — Earn yield on USDC, USD, and USDT holdings
* Batch endorsements — Group multiple operations for single combined approval
* Enhanced trusted counterparties — Support for multiple wallet addresses per counterparty
* Device management dashboard — View and manage all devices connected to your account
**Improvements**
* Faster approval notifications — Real-time push notifications for pending approvals
* Improved QR code scanning — Better device camera integration for QR wallet connections
* Enhanced activity filtering — Filter by counterparty, operation type, and custom tags
* Better wallet recovery — Streamlined recovery process for lost devices
**Fixes**
* Fixed occasional approval timeout issues
* Resolved edge cases with multi-signature quorum calculations
* Improved handling of extremely large transaction amounts
* Fixed formatting of transaction timestamps in activity export
**Known Issues**
* Stablecoin swap rates may have up to 2-minute delays during high network congestion
* Large activity exports (>10,000 transactions) may take 30+ seconds to generate
### Version 2.4.0 (December 2025)
**New Features**
* Admin policy customization — Define different approval rules for administrative changes
* Vault-specific roles — Assign different roles to users in different vaults
* Time-based policy rules — Set different approval requirements by time of day or day of week
* Organization recovery document — Generate encrypted recovery credentials for emergency access
**Improvements**
* Policy rule priority display — Visual indicator of rule matching order
* Bulk user addition — Add multiple team members at once (CSV import)
* Enhanced policy templates — Pre-built policy configurations for common scenarios
* Better policy testing — Simulate operations to see which rules would apply
**Fixes**
* Fixed subquorum member removal edge cases
* Resolved duplicate rule detection
* Improved policy change approval workflow
* Fixed occasional UI lag with large rule sets (50+ rules)
### Version 2.3.0 (November 2025)
**New Features**
* Trusted counterparties — Pre-approve organizations for streamlined transfers
* Smart contract interaction — Direct contract call support for advanced DeFi users
* Advanced asset management — Better wallet organization and naming
* Policy rule suggestions — Get recommendations based on your transaction patterns
**Improvements**
* Faster vault creation — Reduced from 3-5 steps to 2-3 steps
* Improved deposit confirmation times — More accurate network fee estimation
* Enhanced security key management — Better organization of encryption keys
* Clearer error messages — More helpful feedback when operations fail
**Fixes**
* Fixed withdrawal to new addresses occasionally failing approval
* Resolved rare race condition in concurrent approvals
* Improved handling of network timeouts during high traffic
* Fixed policy rule condition matching for edge cases
### Version 2.2.0 (October 2025)
**New Features**
* DApp connection support — Connect Porto wallets to Uniswap, Aave, and other protocols
* Biometric device management — Enable/disable devices, manage Face ID/Touch ID setup
* Enhanced activity history — Export activity as CSV or PDF for compliance
* Policy rule templates — Pre-configured rules for common approval scenarios
**Improvements**
* Faster transaction approval notifications
* Better handling of stablecoin swaps on high-volume days
* Improved wallet recovery documentation
* Enhanced key download security controls
**Fixes**
* Fixed occasional 404 errors when accessing older vault history
* Resolved issue with large withdrawal approvals timing out
* Fixed edge case where policy changes wouldn't apply immediately
* Improved reliability of encrypted backups
### Version 2.1.0 (September 2025)
**New Features**
* Encrypted backups — Automatic encrypted backups of account data and recovery keys
* Key download preferences — Control when and where keys can be downloaded
* Enhanced quorum structures — Support for complex nested approval requirements
* Vault policy customization — Configure different approval rules per vault
**Improvements**
* Better rule conflict detection
* Clearer policy change approval flow
* Improved subquorum member management UI
* More granular audit logging
**Fixes**
* Fixed issue with 3-of-5 quorum approvals
* Resolved problem where removed users still appeared in activity logs
* Fixed encrypted backup decryption on some devices
* Improved handling of concurrent policy edits
### Version 2.0.0 (August 2025)
**Major Release**
* Complete UI redesign with Latitude design system
* Performance improvements — 50% faster operation approvals
* New navigation structure — Reorganized to match logical workflows
* Enhanced mobile experience — Better touch targets, optimized for smaller screens
**New Features**
* Multi-device support — Use Porto on multiple phones/tablets with synchronized access
* Advanced policy management — Create complex approval rules with conditions
* Role-based access control — Different permissions for different users
* Better activity search — Full-text search across all transactions
**Breaking Changes**
* Old password reset links no longer valid (use "Forgot password" on login screen)
* Some older device recovery methods no longer supported
### Version 1.9.0 (July 2025)
**New Features**
* Vault overview dashboard — See all vaults and recent activity at a glance
* Enhanced withdrawal confirmation — More details before submitting withdrawals
* Improved trusted destination management — Bulk operations and better organization
* Better network fee estimation
**Improvements**
* Faster app startup time
* Clearer permission explanations
* Better handling of very long addresses
* Improved support for longer organization names
### Version 1.8.0 (June 2025)
**New Features**
* Receive address generation for multiple assets
* Improved deposit tracking
* Basic policy configuration
* Enhanced security settings
**Fixes**
* Various UI refinements
* Performance optimizations
* Bug fixes
## Future roadmap
**Planned for Q1 2026**
* Enhanced analytics dashboard
* White-label support for enterprise customers
* Advanced audit reporting
* Integration with external accounting software
**Planned for Q2 2026**
* Additional blockchain support (Polkadot, Aptos)
* Advanced trading integrations
* Improved tax reporting features
* Multi-language support
**Exploring**
* Hardware wallet integration
* Mobile app for Android
* Advanced analytics and reporting
* Custom DApp development toolkit
## Version support
* **Current version (2.5.0):** Fully supported
* **Previous versions (2.4.x):** Security updates only
* **Older versions (2.3.x and earlier):** No longer supported; upgrade recommended
## How to update
Porto updates are typically installed automatically. To check your version:
From the home screen, tap **Settings**.
Scroll to the bottom and tap **About** or **App info**.
You'll see your current Porto version and when it was last updated.
If an update is available, you'll see an **Update** button. Tap it to install the latest version.
Updates are usually small (1-5 MB) and download quickly. You'll need to sign back in after updating.
## Reporting issues
If you encounter a bug or issue:
1. **Note the version** — Check your current Porto version (Settings > About)
2. **Document the issue** — Write down exactly what happened, what you were trying to do
3. **Include steps to reproduce** — How can someone else recreate the problem?
4. **Provide details** — Your device type (iPhone, iPad), iOS version, network type (Wi-Fi or mobile)
5. **Contact support** — Reach out to your account manager or Porto support team
## Security updates
We release security updates as needed outside the regular release cycle. Security updates are important and should be installed immediately.
* **Critical security issues** — Deployed within 24 hours
* **High-severity issues** — Deployed within 48-72 hours
* **Medium-severity issues** — Included in next regular release
Security advisories are communicated to all affected organizations.
## Feedback and feature requests
We welcome feedback on Porto. To request a feature or report an issue:
1. **Go to Settings** — Tap **Settings** > **Send feedback**
2. **Describe your idea** — Explain what you'd like to see or what's not working
3. **Provide context** — Include your use case and why the feature matters
4. **Submit** — Your feedback goes directly to the Porto product team
Popular feature requests are tracked and prioritized for future releases.
## API changelog
For developers integrating with Porto APIs, see the separate API changelog:
* [Porto API Reference](/knowledge-base/porto/api-reference)
* [API Breaking Changes](/knowledge-base/porto/api-breaking-changes)
* [SDK Release Notes](/knowledge-base/porto/sdk-releases)
# API keys
Source: https://docs.anchorage.com/knowledge-base/porto/developers/api-keys
Generate, use, revoke, and rotate API access keys to authenticate requests to the Anchorage Digital API.
You're viewing **Porto** developer documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/developers/setting-up)
An API key authenticates your requests to the Anchorage Digital API. Each key is scoped to a [permission group](/knowledge-base/porto/developers/permission-groups) that defines what it can do, so create the group you need before you generate the key.
## How to generate an API key
In the **Developers**, then **API 2.0** section of the web dashboard, select **Create API key**.
The web dashboard supports in-app key generation, or you can bring your own keys. Use the widget below to generate a key pair in this browser session, or run the Python script manually.
This in-app widget is intended for staging and testing only. For production key pairs, use the Python script below or your own key generation tooling instead.
We can't yet guarantee we have every control in place to safely generate and handle keys on your behalf. Generating your own keys keeps that risk with you, rather than shifting it to Anchorage Digital.
```python theme={null}
# https://pypi.org/project/PyNaCl/
import nacl
import nacl.signing
import secrets
seed = secrets.token_bytes(32)
signing_key = nacl.signing.SigningKey(seed)
print('Signing key:')
print(signing_key.encode().hex())
print('Public key:')
print(signing_key.verify_key.encode().hex())
```
Select the permission group you created, and use the public key from the previous step to create your API key. Selecting certain permission groups requires additional quorum approval before the key can be used.
Copy the API key immediately — it isn't displayed again, and keys aren't recoverable. If you lose a key, revoke it and generate a new one.
When you create a key, you'll work with three values:
1. **API access key** — sent on every request as `Api-Access-Key`.
2. **Ed25519 public key** — registered during key generation. Use the Anchorage Digital-generated one or bring your own.
3. **Ed25519 private signing key** — kept locally to produce signatures before a call.
## Using an API key
Every request is made over HTTPS and includes your access key in the `Api-Access-Key` header.
```bash theme={null}
curl --request GET \
--url https://api.anchorage-staging.com/v2/apikey \
--header 'Api-Access-Key: '
```
Sensitive endpoints also require a request signature, passed as `Api-Timestamp` and `Api-Signature`.
```bash theme={null}
curl --request POST \
--url https://api.anchorage-staging.com/v2/transactions/withdrawal \
--header 'Api-Access-Key: ' \
--header 'Api-Signature: ' \
--header 'Api-Timestamp: ' \
--header 'Content-Type: application/json' \
--data '
{
"amount": "1000.00000000",
"assetType": "BTC",
"description": "Internal ID: #12838927347",
"idempotentId": ""
}
'
```
See [Signing requests](/knowledge-base/porto/developers/request-signing) for the full signature recipe before making sensitive calls.
## Revoking an API key
To revoke a single key, select the three-dot menu next to the key and select **Revoke**. To revoke every key in a group at once, delete the [permission group](/knowledge-base/porto/developers/permission-groups) the keys belong to.
## Rotating API keys
There's no dedicated rotation endpoint. You rotate a key yourself by revoking the active key and creating a new one tied to the permission group you want.
Generate a new API key and assign it to the desired permission group, following the steps above. Update your integration to use the new key.
Once the new key is in place and confirmed working, revoke the previous key.
Rotate keys on a regular schedule, and immediately if a key may have been exposed. Creating the replacement before revoking the old key avoids any gap in access.
# FAQs
Source: https://docs.anchorage.com/knowledge-base/porto/developers/faqs
Frequently asked questions about the Anchorage Digital API, devices, and account management.
You're viewing **Porto** developer documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/developers/setting-up)
Find answers grouped by topic — transfers, quorum, onboarding, devices, API access, and network fees.
## Transfers and withdrawals
Withdrawals require quorum approval; transfers do not. Transfers are also more configurable — specifically in how network fees are charged — and allow you to queue multiple transfers from the same wallet simultaneously, assuming sufficient funds.
See the [Transfers vs. withdrawals](/knowledge-base/porto/developers/move-money/transfers-vs-withdrawals) guide and the Transactions section of the API reference for more information.
All external withdrawal requests made via API and the iOS app go through quorum approval and Anchorage Digital risk review. You can add "trusted destinations" and notify your client experience manager to ensure all transfers to non-approved destinations are rejected.
## Quorum and approvals
A quorum authenticates organizational intent — ensuring that initiated transactions align with your organization's governing structure. Quorums are required both internally at Anchorage Digital and for client operations.
New clients must onboard a minimum of three admins. All initial users are admins. From there, new users, vaults, and policies are established through an admin quorum.
Yes. All transactions require a valid quorum of unique, unforgeable cryptographic signatures from multiple organization members. Quorums are configurable per vault as any M-of-N.
For example, a company with five employees authorized to transfer funds might require three of five approvals per transaction. You can also specify a required user for any quorum and use different quorum settings per vault within an account.
## Onboarding and user management
The new member should download the Porto by Anchorage Digital app from the Apple App Store. Once the app is installed, an admin must generate a QR code:
**Admin steps:**
1. Tap the gear icon ⚙️ at the lower right of the app, then tap **Users**.
2. Tap the add icon ➕ at the top right.
3. Follow the prompts to set policies and vaults.
4. Share the unique QR code with the new user (screenshot and email if not in the same location).
**New user steps:**
1. Scan the QR code in the Porto iOS app.
2. Input preliminary KYC information including basic personal data, voice, and biometric training.
3. Wait for quorum approval.
The initiating admin will be prompted for biometric approval. A second approver is then required. Finally, Anchorage Digital compliance reviews the new user's PII and completes due diligence before approving. For the full flow, see [Adding users](/knowledge-base/porto/getting-started/adding-users).
## Devices and security
Anchorage Digital supports iOS devices only — iPhones and iPads — due to the secure enclave within these devices. Without an iPhone, you cannot access the app, web dashboard, or member quorum. You can still call the APIs using keys created and shared during onboarding.
Device security is critical for safeguarding accounts and signing on-chain transactions. If other devices release similar functionality, Anchorage Digital will re-evaluate support at that time.
**Supported iOS devices:**
* iPhone 8, 8 Plus, X, XS, XS Max, XR, 11, 11 Pro, 11 Pro Max, SE (2nd gen), 12, 12 Pro, 12 mini, 13, 13 Pro, 13 mini
* iPad (5th gen and later), mini 4, mini (5th and 6th gen), Air 2, Air (3rd and 4th gen), Pro (all versions)
This is self-serve—you don't need to contact anyone or have the device marked as lost. On your old device, go to **Settings** and tap **Replace my device** to generate a QR code. Install the app on the new phone, scan the QR code, and confirm with biometrics. See [Device management](/knowledge-base/porto/getting-started/device-management) for the full steps.
Inform your client experience manager at Anchorage Digital immediately. The device will be marked as "lost" and deactivated. When you get a new device, your team can help you recover access. Contact Anchorage Digital for support.
This flow is only for devices that are gone. If you still have your old device, use the self-serve replace-device flow above instead—see [Device management](/knowledge-base/porto/getting-started/device-management).
## API access and authentication
| Environment | URL |
| ----------- | --------------------------- |
| Production | `https://api.anchorage.com` |
If your network restricts inbound traffic, allowlist the IP addresses Anchorage Digital sends requests from — for example, webhook deliveries to your endpoints. Allowlist the full set below, as requests can originate from any of these addresses.
| Environment | IP addresses |
| ----------- | ------------------------------------------------- |
| Production | `34.182.59.208`, `34.83.146.129`, `35.203.149.37` |
See the [Request signing](/knowledge-base/porto/developers/request-signing) page for full instructions and reference client scripts.
The default is to require a signature; read-only endpoints are the exception. Signatures are optional unless explicitly required but are encouraged for all requests — if provided, they will be verified.
Endpoints that require signing will specify the `Api-Signature` and `Api-Timestamp` headers as additional parameters and require an Ed25519 signature alongside the API key.
Yes. Revoke a key via the web dashboard or by emailing [portohelp@anchorage.com](mailto:portohelp@anchorage.com).
Revoked keys cannot be reinstated. A new key must be created. You do not need quorum approval or risk review to create a new key using an existing permission group.
To revoke: go to the **API** section of the web dashboard, select the three-dot icon next to the key, and select **Revoke**.
Only admin users with the correct access credentials can revoke API keys. Any user (admin, member, view-only) can view permission group details and past keys, but no user can see the actual hexadecimal key value.
## Network and gas fees
The wallet must hold sufficient balance to cover transaction fees — an estimated balance for withdrawals, staking, and smart contract operations, and a fixed fee threshold for API-initiated transfers.
Gas fees are calculated by multiplying the gas limit (maximum gas willing to spend) by the gas price (ETH per gas unit). They are paid in ETH and used to protect the network and incentivize validators.
As of January 24, 2024, the threshold for ETH is set to 0 ETH. Actual fees vary by network conditions at broadcast time.
The wallet must hold an ETH balance calculated from gas limit estimates, multipliers for gas limit and price, and priority fees.
Anchorage Digital sets a MaxFee to ensure users don't overpay while still having enough for transaction processing. Priority fee is set to 0.01 Gwei.
For ERC-20 withdrawals and transfers, avoiding dust is not possible due to the non-deterministic nature of gas for smart contract interactions. For ETH transfers, it is theoretically possible to avoid dust by specifying maxFee and maxPriorityFee to consume the remaining balance, but this is not currently supported on the platform.
# Deposit
Source: https://docs.anchorage.com/knowledge-base/porto/developers/move-money/deposit
Receive digital assets into Anchorage Digital wallets and vaults.
You're viewing **Porto** developer documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/developers/setting-up)
A **deposit** is how funds enter Anchorage Digital. Receiving funds never requires quorum approval and never incurs a fee for the receiver. To accept funds, you create a place for them to land—a wallet and deposit address for digital assets—then share those details with the sender and watch for arrival.
## No quorum, no fee
Deposits are inbound, so there's no per-transaction quorum and no receiver-side network fee. The controls that matter for deposits are identity (attributing unknown senders) and address integrity (verifying the address you share is genuinely yours).
## Deposit guides
Create a wallet and deposit address to receive digital assets, then track and attribute the deposit.
## Create a wallet and address
A wallet lives inside a vault and is created for a specific asset network. Create one with the **Deposit** button in the web dashboard or iOS app, or via API.
```json theme={null}
// POST /v2/vaults/{vaultId}/wallets
{
"networkId": "{asset network ID}",
"walletName": "Bitcoin Mainnet - Wallet 1"
}
```
Provision a deposit address for an existing wallet:
```bash theme={null}
curl --request POST \
--url https://api.anchorage-staging.com/v2/wallets/{walletId}/addresses \
--header 'Api-Access-Key: {API key}' \
--header 'accept: application/json'
```
Creating addresses requires the `Create address` permission. Reading wallets and addresses requires `Read vault activity`.
## Monitor arrivals
Subscribe to webhooks to be notified when funds land. See [Webhooks](/knowledge-base/porto/developers/webhooks/webhooks-overview). For digital assets, delivery waits on on-chain confirmation, typically around two confirmations depending on the blockchain.
## Deposit APIs
| API | Description |
| :-------------------------- | :--------------------------------------------------------- |
| Create a wallet in a vault | Creates a wallet for an asset network to receive deposits. |
| Provision a deposit address | Generates a new deposit address for a wallet. |
| List addresses for an asset | Returns existing deposit addresses for an asset. |
# Crypto deposit
Source: https://docs.anchorage.com/knowledge-base/porto/developers/move-money/deposit/crypto
Receive digital assets end to end: create and verify a wallet address, then track the incoming deposit.
You're viewing **Porto** developer documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/developers/setting-up)
Receiving a digital asset is a single end-to-end flow: create a wallet and deposit address, verify and share it, then track the incoming deposit. This page walks the full path. For the shared wallet and address mechanics, see [Deposit](/knowledge-base/porto/developers/move-money/deposit).
Once funds are inbound, `GET /v2/transactions` shows how much arrived, in what asset, from which address, and its on-chain status.
## Deposit flow
Call `POST /v2/vaults/{vaultId}/wallets`, passing the `networkId` and a `walletName`.
Call `POST /v2/wallets/{walletId}/addresses`, or list existing addresses with `GET` on the addresses endpoint.
Anchorage Digital signs every deposit address so you can confirm it was generated for your organization and hasn't been tampered with. Confirm both that the signature is valid and that the signed address matches the one you intend to share. See [Address verification](/knowledge-base/api-reference/address-verification).
Share the verified address with the sender, who sends only the correct asset on the correct network.
Subscribe to [webhooks](/knowledge-base/porto/developers/webhooks/webhooks-overview) to be notified on arrival, then read the deposit with `GET /v2/transactions`:
```json theme={null}
{
"data": [
{
"id": "0e2b2f9d8d104f1e960b28567255045f",
"transactionType": "DEPOSIT",
"status": "SUCCESS",
"assetType": "ETH",
"amount": {
"quantity": "5.0",
"assetType": "ETH",
"currentPrice": "3450.12",
"currentUSDValue": "17250.60"
},
"blockchainTxId": "0x84ddb76708d570101db89fd27b1717484c54417c9f32c63052cdfac9a0bfc0a2",
"sourceAddresses": ["0xb4Bb4E3D7f35ede58d99F5e2b8B04f7AC87f9c88"],
"destinationAddresses": ["0x39d9f4640b98189540A9c0Ede2b8B04f7AC8aa21"],
"dateTime": "2026-06-24T14:08:31.000Z",
"vaultId": "1c920f4241b78a1d483a29f3c24b6c4c",
"vaultName": "Treasury Vault",
"walletId": "d24b424293c0d64c6194f52801b3d293"
}
],
"page": { "next": null }
}
```
## Address integrity
Always verify a deposit address before use. The addresses API returns a signature and metadata that prove the address belongs to your vault and network. See [Address verification](/knowledge-base/api-reference/address-verification) for the V1 and V2 schemes.
## Failed and unrecognized deposits
Sending the wrong asset type to an Anchorage Digital address results in a failed deposit. An asset sent on a different chain than the address is not recognized. If the address is correct but the asset is unsupported—for example, an unsupported ERC-20 sent to an ETH address—contact [portohelp@anchorage.com](mailto:portohelp@anchorage.com).
# Operate
Source: https://docs.anchorage.com/knowledge-base/porto/developers/move-money/operate
Monitor movement status and understand network fees once assets are in motion.
You're viewing **Porto** developer documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/developers/setting-up)
Once money is moving, two things matter day to day: knowing the status of each movement, and understanding the network fees attached to it.
Follow transfers, withdrawals, and deposits to completion.
How blockchain fees work.
# Track movement status
Source: https://docs.anchorage.com/knowledge-base/porto/developers/move-money/operate/track-status
Follow transfers, withdrawals, and deposits to completion using polling or webhooks.
You're viewing **Porto** developer documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/developers/setting-up)
Every movement can be followed two ways: poll the read APIs, or subscribe to webhooks for event-driven updates.
## Read APIs
| Movement | Poll |
| :--------- | :------------------------------------------------------- |
| Transfer | `GET /v2/transfers`, or `GET /v2/transfers/{transferId}` |
| Withdrawal | `GET /v2/transactions`, or `GET /v2/transactions/{id}` |
| Deposit | `GET /v2/transactions` |
Transfers and withdrawals use different status vocabularies. Transfers move through `QUEUED`, `IN_PROGRESS`, `COMPLETED`, and `FAILED`. Withdrawals move through `NEEDS_APPROVAL`, `INPROGRESS`, `SUCCESS`, `FAILURE`, `REJECTED`, and `EXPIRED`. See [Crypto transfer](/knowledge-base/porto/developers/move-money/transfer/crypto) and [Crypto withdrawal](/knowledge-base/porto/developers/move-money/withdraw/crypto) for the full lifecycles.
## Webhooks
Subscribe to webhooks to receive updates as operations and transactions change state, instead of polling. For digital assets, delivery waits on on-chain confirmation, typically around two confirmations. See [Webhooks](/knowledge-base/porto/developers/webhooks/webhooks-overview).
### Correlate a webhook to its transaction
Webhook events are lightweight—each carries the identifier of the affected record, not its full detail. On receipt, fetch the record and inspect it:
A `deposit.*`, `transfer.*`, or `withdrawal.*` event arrives with the transaction identifier. See [Webhooks](/knowledge-base/porto/developers/webhooks/webhooks-overview) for the event catalog and payload fields.
Look it up with the matching read API: transfers via `GET /v2/transfers/{transferId}`; deposits and withdrawals via `GET /v2/transactions/{id}`.
Read `transactionType` (`DEPOSIT`, `WITHDRAW`, or `TRANSFER`) together with `sourceAddresses` and `destinationAddresses` to classify what happened and where the funds moved.
### Tell an internal deposit from an external one
An internal transfer between your own wallets lands as a `DEPOSIT` on the destination wallet, the same shape as a deposit from an outside sender. To distinguish them, compare the deposit's `sourceAddresses` against the addresses you manage (from `GET /v2/wallets` and the addresses API): a match means the funds came from one of your own wallets; otherwise the sender is external.
The transfers API identifies records by `transferId`, which isn't always a UUID. Match on the value exactly as returned rather than assuming a format.
## Idempotency and retries
Provide an `idempotentId` per request so an interrupted call can be retried safely without double-spending. For status codes, rate limits, and cursor pagination, see [Handling errors, retries, and pagination](/knowledge-base/api-reference/errors-pagination).
# Overview
Source: https://docs.anchorage.com/knowledge-base/porto/developers/move-money/overview
Understand how deposits, transfers, and withdrawals work within Anchorage Digital's security model.
You're viewing **Porto** developer documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/developers/setting-up)
At Anchorage Digital, every movement runs through the same controls that secure the assets themselves: segregated, HSM-secured vaults governed by policy-based quorum. The money-movement APIs are built so you can automate and scale movement without stepping outside that security model.
Funds come **in** through a deposit, sit in your wallets and vaults, and move **out** in one of two ways. Which way you use depends on two things: how much per-transaction control you want, and where the funds are going.
## Start here
* **Receive funds** — Create wallets and deposit addresses to bring digital assets into Anchorage Digital. See [Deposit](/knowledge-base/porto/developers/move-money/deposit).
* **Transfer** — Move assets between your wallets or to a trusted destination, without per-transaction quorum. See [Crypto transfer](/knowledge-base/porto/developers/move-money/transfer/crypto).
* **Withdraw** — Move assets with quorum approval on every request. See [Crypto withdrawal](/knowledge-base/porto/developers/move-money/withdraw/crypto).
## The mental model
A deposit is the only way funds enter Anchorage Digital, and receiving never requires quorum. Everything else is a movement out of—or between—your holdings. There are exactly two kinds, split by approval model.
**Transfers** move assets without quorum approval on each request, which suits recurring or high-frequency flows. In exchange, they require one-time setup: an allowlisted destination and a permission group scoped to the operation.
**Withdrawals** require quorum approval on every request, giving you control over each individual movement through your vault policies.
Both transfers and withdrawals can go to an **internal** wallet you own or to an **external** destination outside Anchorage Digital. External movements add one requirement: the destination must be an allowlisted trusted destination.
This guide assumes you're familiar with quorum and approval rules. If you're not, start with [admin policies](/knowledge-base/porto/policies/admin-policies).
## Where quorum applies
| Action | Quorum on each request? |
| :--------------------------------------- | :---------------------------------------------- |
| Deposit (receive) | |
| Transfer (internal or external) | (approval is front-loaded into setup) |
| Withdrawal (internal or external) | |
| Adding or removing a trusted destination | |
## Support at a glance
Deposits are supported for digital assets. Trusted destinations for digital assets can be managed via API and the web platform.
### Trusted destination required
Trusted destinations (allowlisted addresses) let you pre-approve an external destination for use across the iOS app, web dashboard, and APIs.
| | Internal transfer API | External transfer API | Withdrawal API |
| :----------------- | :-------------------- | :-------------------- | :------------- |
| **Digital assets** | | | \* |
If you want to restrict Withdrawal API destinations to only trusted/allowlisted addresses, reach out to your point of contact to enable this.
## Before you move money: prerequisites
Internal movements work with standard API access. External movements—external transfers and withdrawals to new destinations—require one-time setup, and quorum is required at several of these steps.
1. **Allowlist a trusted destination** — Pre-approve the external address. Adding a trusted destination requires quorum approval. See [Trusted destinations](/knowledge-base/porto/developers/move-money/setup/trusted-destinations).
2. **Configure external transfer permissions** — Enable external transfers on the permission group the key uses. This permission is configurable: scope it to specific trusted destinations, or allow any quorum-approved trusted destination. See [Permission groups and API keys](/knowledge-base/porto/developers/move-money/setup/permission-groups).
3. **Create and activate an API key** — API keys with external transfer or withdrawal permissions require quorum approval before they can be used. See [Authentication](/knowledge-base/porto/developers/move-money/setup/authentication).
Keep internal and external transfer permissions in separate permission groups and API keys. Do not combine them.
## Related
* [Transfers vs. withdrawals](/knowledge-base/porto/developers/move-money/transfers-vs-withdrawals) — The full comparison of the two approval models.
* [Trusted destinations](/knowledge-base/porto/developers/move-money/setup/trusted-destinations) — Allowlist external addresses.
* [Network and gas fees](/knowledge-base/porto/developers/network-gas-fees) — How blockchain fees work.
# Authentication and request signing
Source: https://docs.anchorage.com/knowledge-base/porto/developers/move-money/setup/authentication
Authenticate every API request and sign sensitive move-money operations with Ed25519.
You're viewing **Porto** developer documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/developers/setting-up)
Every request includes your `Api-Access-Key` header. Sensitive operations—including transfers, withdrawals, and trusted-destination management—additionally require an **Ed25519 request signature**, supplied in the `Api-Signature` and `Api-Timestamp` headers and generated from your private key over the canonical request.
## Base URLs
| Environment | Base URL |
| :---------- | :----------------------------- |
| Production | `https://api.anchorage.com/v2` |
## Child control keys for self-custody
Self-custody organizations send one additional header when initiating transfers through the API: `Api-Child-Control-Key`. It carries the source wallet's child control key as 64 lowercase hex characters, derived locally from your Master Control Key. Anchorage Digital's hardware security modules cannot decrypt a self-custody wallet's signing keys without it, and the Master Control Key itself is never sent. Derive the value fresh for each transfer using the wallet's `derivationPath`; see [Generating child control keys](/knowledge-base/porto/developers/move-money/transfer/generating-child-control-keys) for the derivation recipe and reference code.
For the exact signing recipe and code samples, see [Signing requests](/knowledge-base/porto/developers/request-signing). For how authentication, keys, and permission groups fit together, see [Setting up](/knowledge-base/porto/developers/setting-up).
# Permission groups and API keys
Source: https://docs.anchorage.com/knowledge-base/porto/developers/move-money/setup/permission-groups
Configure the permissions and API keys needed for transfers, withdrawals, and trusted destination management.
You're viewing **Porto** developer documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/developers/setting-up)
An **API key** authenticates requests. A **permission group** controls which vaults and operations the keys in it can use. Move-money setup is mostly a matter of putting the right permissions on the right group, then activating a key against it.
## Permission levels
* **Global permissions** apply across all your vaults (for example, `Initiate withdrawals`).
* **Vault-level permissions** apply only to the selected vault or its wallets (for example, `Transfer funds`).
## Move-money permissions
| Permission | Level | Used for |
| :---------------------------------------------- | :----- | :-------------------------------------------------------------- |
| `Read` | Vault | Reading balances and transactions. |
| `Create address` | Vault | Creating wallets and deposit addresses. |
| `Transfer funds (within Anchorage Digital)` | Vault | Internal transfers from that vault. |
| `Transfer funds (outside of Anchorage Digital)` | Vault | External transfers from that vault. |
| `Initiate withdrawals` | Global | Withdrawals to external destinations (each still needs quorum). |
| `Manage trusted destinations` | Global | Creating and managing trusted destinations. |
| `Configure webhooks` | Global | Managing webhooks. |
## Activation and segregation
* Keys with external transfer or withdrawal permissions require quorum approval before they can be used.
* Keep internal and external transfer permissions in separate permission groups and API keys. Do not combine them.
* An optional daily transfer limit can be set per permission group, applied across all keys in the group over a rolling 24-hour window. Limits apply per permission group only. Per-account limits spanning multiple endpoints aren't available yet.
Permission groups are created and configured by your organization admin in the web dashboard. See [API keys](/knowledge-base/porto/developers/api-keys) for creating and using keys.
# Trusted destinations
Source: https://docs.anchorage.com/knowledge-base/porto/developers/move-money/setup/trusted-destinations
Allowlist external addresses before making external transfers or withdrawals.
You're viewing **Porto** developer documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/developers/setting-up)
A **trusted destination** is an allowlisted external address. Adding one requires quorum approval. Once allowlisted, it can be used across the iOS app, web dashboard, and APIs.
## What you can do where
| Operation | API | Web dashboard |
| :------------------------------------------- | :-------- | :------------ |
| View trusted destinations | | |
| Create (digital assets) | | |
| Delete | | |
| Edit | | |
| Batch upload | | |
| Network-level destination (`isNetworkLevel`) | | |
## Sending to your own org's addresses
You can allowlist addresses that belong to your own organization as trusted destinations to tag and label critical internal addresses. This is purely a convenience for recognition — it isn't required for internal movement.
If your concern is avoiding per-transaction quorum when moving assets between your own wallets, use the [internal transfer API](/knowledge-base/porto/developers/move-money/transfer/crypto#internal-transfer) instead. Internal transfers set both `source.type` and `destination.type` to `WALLET` and don't require a trusted destination or allowlisting.
## Create a trusted destination via API
Requires the `Manage Trusted Destinations` permission. Adding a trusted destination requires quorum approval.
```json theme={null}
// POST /v2/trusted_destinations
{
"idempotentId": "{unique ID}",
"trustedDestinations": [
{
"address": "{address}",
"assetType": "{asset}",
"name": "{name}",
"description": "{description}",
"isNetworkLevel": true,
"memo": "{memo}"
}
]
}
```
Set `isNetworkLevel: true` to let the destination receive any asset on that network (digital assets only).
## Connect a trusted destination to an API key
If you're using the Transfers API to transfer to a trusted destination, you need to configure your API key's permission group to allow it. There are two options, set when configuring the **Transfers outside Anchorage** permission on your API key.
### Specific destinations (default)
By default, your API key is scoped to **Specific destinations**. Once a trusted destination has been added and approved, you must also add it to the API key's permission group before you can transfer to it. See [Permission groups and API keys](/knowledge-base/porto/developers/move-money/setup/permission-groups) for the step-by-step flow.
### Any trusted destination
You can select **Any trusted destination** when configuring your key to automatically allowlist all current and future trusted destinations for that key. This removes the need to manually update the permission group each time a new trusted destination is approved.
## APIs
| API | Description |
| :----------------------------------- | :------------------------------------------------------------- |
| List trusted destinations | Returns trusted destinations. |
| Create new trusted destinations | Allowlists one or more destinations. Requires quorum approval. |
| Check status of trusted destinations | Returns the approval status of a pending destination. |
| Delete trusted destination | Removes a destination. |
# Crypto transfer
Source: https://docs.anchorage.com/knowledge-base/porto/developers/move-money/transfer/crypto
Move digital assets between wallets or to an external on-chain address without per-transaction quorum.
You're viewing **Porto** developer documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/developers/setting-up)
A crypto transfer moves digital assets to an internal wallet or an external on-chain address without quorum approval on each request. For shared concepts, external setup, limits, and status monitoring, see [Transfers and withdrawals](/knowledge-base/porto/developers/move-money/transfers-vs-withdrawals). This page covers the crypto-specific payloads and behavior.
`POST /v2/transfers` requires the `Transfer funds` permission and an Ed25519 request signature.
## Internal transfer
Move assets to any wallet you own at Anchorage Digital. No allowlisting is required. Set both `source.type` and `destination.type` to `WALLET`.
```json theme={null}
{
"source": {
"id": "{source wallet ID}",
"type": "WALLET"
},
"destination": {
"id": "{destination wallet ID}",
"type": "WALLET"
},
"assetType": "{asset}",
"amount": "{quantity}",
"transferMemo": "{memo}",
"idempotentId": "{unique ID}"
}
```
## External transfer
Move assets to an external destination that has been allowlisted as a trusted destination. You can identify the destination two ways:
* **`ADDRESS`** — Pass the allowlisted address as `destination.id`. If the asset requires a memo or destination tag, include the matching `assetParameters`.
* **`TRUSTED_DESTINATION`** — Pass the trusted destination ID as `destination.id`. Any memo or destination tag stored on the trusted destination is applied automatically, so you don't submit `assetParameters` yourself. This is the simpler path for assets that need a memo or tag, and it avoids mismatched-memo errors.
```json By address theme={null}
{
"source": {
"id": "{source wallet ID}",
"type": "WALLET"
},
"destination": {
"id": "{trusted destination address}",
"type": "ADDRESS"
},
"assetType": "{asset}",
"amount": "{quantity}",
"transferMemo": "{memo}",
"idempotentId": "{unique ID}",
"assetParameters": "{memo or destination tag, if required}"
}
```
```json By trusted destination theme={null}
{
"source": {
"id": "{source wallet ID}",
"type": "WALLET"
},
"destination": {
"id": "{trusted destination ID}",
"type": "TRUSTED_DESTINATION"
},
"assetType": "{asset}",
"amount": "{quantity}",
"transferMemo": "{memo}",
"idempotentId": "{unique ID}"
}
```
### Fields
| Field | Description |
| :-------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `source.id` / `source.type` | The wallet to send from. Retrieve wallet IDs via `GET /v2/wallets`. |
| `destination.type` | `WALLET` for internal. For external, `ADDRESS` (the allowlisted address as `destination.id`) or `TRUSTED_DESTINATION` (the trusted destination ID as `destination.id`). |
| `assetType` | The asset to move. List supported values via `GET /v2/asset-types`. |
| `amount` | Quantity as a string, without units. |
| `idempotentId` | A client-provided unique ID (for example, a v4 UUID). Use a distinct value per transfer so an interrupted call can be safely retried. |
| `transferMemo` | Optional free-text description carried into the resulting transaction and deposit. |
### Response
A successful request returns `201` with a `transferId` and `status`:
```json theme={null}
{
"data": {
"transferId": "008d3ec72558ce907571886df63ef51594b5bd8cf106a0b7fa8f12a30dfc867f",
"status": "QUEUED"
}
}
```
With `destination.type: ADDRESS`, include the matching `assetParameters` if the asset requires a memo or destination tag. With `destination.type: TRUSTED_DESTINATION`, omit `assetParameters`—the memo or tag stored on the trusted destination is applied automatically.
## Crypto-specific behavior
**Queuing** — Up to 50 transfer requests from the same source wallet can be queued at once. Transfers for the same asset on the same blockchain process one at a time; others stay `QUEUED` until the prior transfer completes or fails. Transfers on different wallets or different blockchains can process in parallel. Transfers expire 24 hours after initiation.
**`assetParameters`** — Required when transferring to institutional wallets that need a memo or destination tag. Supported assets: ATOM, Cosmos, DYDX, HBAR, STX, TIA, XLM, XRP, ZETA.
**`deductFeeFromAmountIfSameType`**
| Value | Behavior |
| :---------------- | :-------------------------------------------------------------------------------------------------- |
| `false` (default) | Network fee is charged in addition to the transfer amount. |
| `true` | Network fee is deducted from the transfer amount, only when the fee and transfer asset types match. |
To transfer a full balance of an asset whose fee is paid in the same asset (for example, BTC), set `deductFeeFromAmountIfSameType: true`. When the source is a `walletId`, fees are deducted from that wallet; when the source is a `vaultId`, fees come from the vault's default wallet (`isDefault: true`).
## Troubleshooting
If an external transfer returns `401`/`403`, check that:
* You're using the correct base URL.
* The destination is an allowlisted trusted destination.
* The permission group has external transfers enabled.
* If your permission is scoped to specific destinations, the destination has been connected to the permission group and endorsed.
Common request-level failures: the source wallet doesn't exist or doesn't support the asset, the amount exceeds available funds, the destination doesn't support the asset, or the key lacks permissions for the source vault.
After a request succeeds, the transfer can still fail at execution if there are insufficient funds to cover the network fee at broadcast time or there's a blockchain-level failure.
# Generating child control keys
Source: https://docs.anchorage.com/knowledge-base/porto/developers/move-money/transfer/generating-child-control-keys
Derive the per-wallet child control key that authorizes self-custody API transfers.
You're viewing **Porto** developer documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/developers/setting-up)
Self-custody organizations hold their wallet keys under a Master Control Key (MCK) that only the client possesses. The wallet private keys stored in Anchorage Digital's hardware security modules are encrypted to your MCK, so Anchorage Digital cannot sign a transaction until you supply the matching per-wallet child control key. To authorize a transfer through the API, derive that child control key from your MCK and send it in the `Api-Child-Control-Key` header of `POST /v2/transfers`.
Never send the Master Control Key itself to Anchorage Digital. Only the derived per-wallet child control key is transmitted. Perform the derivation on infrastructure you control and treat both keys as secrets.
The diagram below shows the full flow: a one-time secure provisioning phase that decodes the Recovery Document's mnemonic and stores the purpose-level extended private key, and a per-transfer phase that derives the wallet's child control key and sends it with the transfer. Each numbered step links to the section of this page that covers it.
## Derivation inputs
| Value | Notes |
| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `mck` | A 32-byte secret, representable as a 24-word BIP39 mnemonic or as a 64-character hex string. Both encodings decode to the same bytes. |
| `derivationPath` | Per-wallet value returned by `GET /v2/wallets/{walletId}`. The value never changes for a given wallet. Always fetch it from the API and pass it unmodified to the derivation code below, which walks its steps; never construct a path yourself or attach meaning to its components. |
The derivation is deterministic: the same MCK and derivation path always produce the same child control key, so you can derive on demand and avoid storing child keys.
## How derivation works
The scheme is standard BIP39 and BIP32, so mature libraries cover all of the cryptography:
1. Decode the MCK. If you hold the 24-word mnemonic, decode it to the 32-byte entropy (`mckFromMnemonic` below). If you hold the MCK as a hex string, hex-decode it to the 32 bytes.
2. Re-encode the entropy as a BIP39 mnemonic and stretch it into the 64-byte BIP39 seed with an empty passphrase.
3. Create a BIP32 master key from the seed and insert Anchorage Digital's hardened purpose step `1097753448'` as the first step after `m`. The wallet's `derivationPath` is relative to this purpose level.
4. Derive the remaining path steps and take the resulting node's 32-byte private key.
5. Hex-encode those 32 bytes (64 lowercase hex characters) for the `Api-Child-Control-Key` header.
## Derive a child control key
```typescript theme={null}
/**
* Anchorage Digital child control key derivation reference implementation.
*
* Required dependencies:
* @scure/bip32@^1.7.0
* @scure/bip39@^1.6.0
*/
import { HDKey } from "@scure/bip32";
import { entropyToMnemonic, mnemonicToEntropy, mnemonicToSeedSync } from "@scure/bip39";
import { wordlist } from "@scure/bip39/wordlists/english";
// First derivation step after "m" for every Anchorage control key. The
// wallet derivationPath returned by GET /v2/wallets/{walletId} is
// relative to this hardened purpose level.
const ANCHORAGE_PURPOSE = "1097753448'";
/**
* Decode the Recovery Document's 24-word mnemonic into the 32-byte MCK.
* The BIP39 checksum is validated.
*/
export function mckFromMnemonic(mnemonicWords: string): Uint8Array {
return mnemonicToEntropy(mnemonicWords, wordlist);
}
/**
* Derive a wallet's 32-byte child control key from the MCK.
* `derivationPath` is the value returned by GET /v2/wallets/{walletId}.
*/
export function deriveChildControlKey(mck: Uint8Array, derivationPath: string): Uint8Array {
const mnemonic = entropyToMnemonic(mck, wordlist);
const seed = mnemonicToSeedSync(mnemonic);
const path = ["m", ANCHORAGE_PURPOSE, ...pathSteps(derivationPath)].join("/");
const node = HDKey.fromMasterSeed(seed).derive(path);
if (!node.privateKey) {
throw new Error(`no private key at ${derivationPath}`);
}
return node.privateKey;
}
function pathSteps(derivationPath: string): string[] {
const steps = derivationPath.split("/").filter((step) => step !== "");
if (steps[0] !== "m") {
throw new Error(`derivation path must start with 'm': ${derivationPath}`);
}
// BIP32 hardened steps may be written with a trailing h; HDKey expects '.
return steps.slice(1).map((step) => (step.endsWith("h") ? `${step.slice(0, -1)}'` : step));
}
export function toHex(bytes: Uint8Array): string {
return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
}
// Example
const mnemonic =
"wish length people install bundle crop jacket wolf stove calm blind ramp " +
"solution agent bean exhibit buddy knee club correct hurt riot rice either";
const mck = mckFromMnemonic(mnemonic);
const childKey = deriveChildControlKey(mck, "m/0/0/0");
console.log(`Api-Child-Control-Key: ${toHex(childKey)}`);
// Api-Child-Control-Key: 85a087d378cc3e215361aa764e48b6fbafd6a44805bcc371d7b4ddc80ea46f81
```
```python theme={null}
"""Anchorage Digital child control key derivation reference implementation.
Required dependency:
bip-utils>=2.9
"""
from bip_utils import (
Bip32Slip10Secp256k1,
Bip39MnemonicDecoder,
Bip39MnemonicGenerator,
Bip39SeedGenerator,
)
# First derivation step after "m" for every Anchorage control key. The
# wallet derivationPath returned by GET /v2/wallets/{walletId} is
# relative to this hardened purpose level.
ANCHORAGE_PURPOSE = "1097753448'"
def mck_from_mnemonic(mnemonic_words: str) -> bytes:
"""Decode the Recovery Document's 24-word mnemonic into the 32-byte MCK.
The BIP39 checksum is validated.
"""
return bytes(Bip39MnemonicDecoder().Decode(mnemonic_words))
def derive_child_control_key(mck: bytes, derivation_path: str) -> bytes:
"""Derive a wallet's 32-byte child control key from the MCK.
derivation_path is the value returned by GET /v2/wallets/{walletId}.
"""
mnemonic = Bip39MnemonicGenerator().FromEntropy(mck)
seed = Bip39SeedGenerator(mnemonic).Generate()
node = Bip32Slip10Secp256k1.FromSeed(seed)
for step in _path_steps(derivation_path):
node = node.ChildKey(_step_index(step))
return node.PrivateKey().Raw().ToBytes()
def _path_steps(derivation_path: str) -> list[str]:
steps = [s for s in derivation_path.split("/") if s]
if not steps or steps[0] != "m":
raise ValueError(f"derivation path must start with 'm': {derivation_path!r}")
return [ANCHORAGE_PURPOSE, *steps[1:]]
def _step_index(step: str) -> int:
# BIP32 hardened steps may be written with a trailing ' or h.
hardened = step.endswith(("'", "h"))
index = int(step[:-1] if hardened else step)
return index + 0x80000000 if hardened else index
if __name__ == "__main__":
mnemonic = (
"wish length people install bundle crop jacket wolf stove calm blind ramp "
"solution agent bean exhibit buddy knee club correct hurt riot rice either"
)
mck = mck_from_mnemonic(mnemonic)
child_key = derive_child_control_key(mck, "m/0/0/0")
print(f"Api-Child-Control-Key: {child_key.hex()}")
# Api-Child-Control-Key: 85a087d378cc3e215361aa764e48b6fbafd6a44805bcc371d7b4ddc80ea46f81
```
```go theme={null}
// Anchorage Digital child control key derivation reference implementation.
//
// Required dependencies:
//
// github.com/btcsuite/btcd/btcutil v1.1.6
// github.com/tyler-smith/go-bip39 v1.1.0
package derivecontrolkey
import (
"fmt"
"strconv"
"strings"
"github.com/btcsuite/btcd/btcutil/hdkeychain"
"github.com/btcsuite/btcd/chaincfg"
bip39 "github.com/tyler-smith/go-bip39"
)
// anchoragePurpose is the first derivation step after "m" for every
// Anchorage control key, as a hardened index. The wallet derivationPath
// returned by GET /v2/wallets/{walletId} is relative to this purpose level.
const anchoragePurpose uint32 = 1097753448 + hdkeychain.HardenedKeyStart
// MCKFromMnemonic decodes the Recovery Document's 24-word mnemonic into
// the 32-byte MCK. The BIP39 checksum is validated.
func MCKFromMnemonic(mnemonicWords string) ([]byte, error) {
return bip39.EntropyFromMnemonic(mnemonicWords)
}
// DeriveChildControlKey derives a wallet's 32-byte child control key from
// the MCK. derivationPath is the value returned by
// GET /v2/wallets/{walletId}.
func DeriveChildControlKey(mck []byte, derivationPath string) ([]byte, error) {
mnemonic, err := bip39.NewMnemonic(mck)
if err != nil {
return nil, err
}
seed := bip39.NewSeed(mnemonic, "")
node, err := hdkeychain.NewMaster(seed, &chaincfg.MainNetParams)
if err != nil {
return nil, err
}
steps, err := pathSteps(derivationPath)
if err != nil {
return nil, err
}
for _, step := range steps {
if node, err = node.Derive(step); err != nil {
return nil, err
}
}
privateKey, err := node.ECPrivKey()
if err != nil {
return nil, err
}
return privateKey.Serialize(), nil
}
func pathSteps(derivationPath string) ([]uint32, error) {
var parts []string
for _, part := range strings.Split(derivationPath, "/") {
if part != "" {
parts = append(parts, part)
}
}
if len(parts) == 0 || parts[0] != "m" {
return nil, fmt.Errorf("derivation path must start with 'm': %q", derivationPath)
}
steps := []uint32{anchoragePurpose}
for _, part := range parts[1:] {
// BIP32 hardened steps may be written with a trailing ' or h.
hardened := strings.HasSuffix(part, "'") || strings.HasSuffix(part, "h")
if hardened {
part = part[:len(part)-1]
}
index, err := strconv.ParseUint(part, 10, 32)
if err != nil || index >= hdkeychain.HardenedKeyStart {
return nil, fmt.Errorf("invalid derivation step %q in %q", part, derivationPath)
}
if hardened {
index += hdkeychain.HardenedKeyStart
}
steps = append(steps, uint32(index))
}
return steps, nil
}
// Example:
//
// mck, _ := MCKFromMnemonic("wish length people install bundle crop jacket wolf stove calm blind ramp solution agent bean exhibit buddy knee club correct hurt riot rice either")
// childKey, _ := DeriveChildControlKey(mck, "m/0/0/0")
// fmt.Printf("Api-Child-Control-Key: %x\n", childKey)
// // Api-Child-Control-Key: 85a087d378cc3e215361aa764e48b6fbafd6a44805bcc371d7b4ddc80ea46f81
```
The mnemonic in the examples is a published test key, not a real organization's MCK. Run your implementation against it and confirm you get the same child control key before using a production Recovery Document.
## Verify byte-parity
The reference implementations above are checked against Anchorage Digital's iOS app to guarantee byte-identical output. Each entry below that carries an `extendedPrivateKey` is pinned to that iOS-produced expectation; the rest are additional derivation-path cases. Point your own client at these vectors and confirm you derive the same child control key for every path before you use it against a real Master Control Key.
```json theme={null}
{
"bip39": [
{
"entropy": "a3fa08c67dfcf74bbe9dfb38e1be41ecbbffd5de15dfefedc158a909f9cbb157",
"mnemonic": "physical space cover winner sorry place whip satoshi decline assume motor sunny say turtle joke room useful host file faith panel total shed topple",
"seed": "ee034014e43a58f89cf3c2a579ae4e08d602b0627d027c2cec3ef7e1aa4e04e1f59cdac13ca9f708f2f5bbe611585816feab84185979feb64211cd3fb464c6b8"
},
{
"entropy": "fc90028b3ab1e467ddc7e6d6a4105f58bcec09c4e27c1d6f70b09846fd746e4a",
"mnemonic": "wish length people install bundle crop jacket wolf stove calm blind ramp solution agent bean exhibit buddy knee club correct hurt riot rice either"
},
{
"entropy": "6436f7db26ed58ee35c74ca283bea063a1fed2bcb0a1e7c3fc87f500eea77f29",
"mnemonic": "goddess response walnut evidence stereo jacket strike trumpet penalty bulb pool shrug cable harsh version before treat cable capable tube auction father witness critic"
}
],
"derivations": [
{
"controlKey": "fc90028b3ab1e467ddc7e6d6a4105f58bcec09c4e27c1d6f70b09846fd746e4a",
"path": "m",
"extendedPrivateKey": "xprv9usvAzZYdL9g4zd3XqVgAc8LEBztwqcSvosDMLZyEx8GDKa7kwzQntu3GcqkaYWgTBLGwURUdyf8TXYyPXxRd1EZCt6zJwVpcyDArib1d26"
},
{
"controlKey": "6436f7db26ed58ee35c74ca283bea063a1fed2bcb0a1e7c3fc87f500eea77f29",
"path": "m",
"extendedPrivateKey": "xprv9v6gKLjRuwmornGiTwcKcFfFuuUo8Zg5hNCkZT2LmxEKc1xeTqNL7w6wD6RyJY9Ys7LTQddRaWU62qcbPcpYWcDEfr3jyfYZSwMbTn3KnrD"
},
{
"controlKey": "6436f7db26ed58ee35c74ca283bea063a1fed2bcb0a1e7c3fc87f500eea77f29",
"path": "m/0'",
"extendedPrivateKey": "xprv9x9bfxtQTWF1oprN1s4JkbhnqU9F5fRje4zWLMVMbEoj9FuFiimVxmqPw8rkrgk31TmaWm5z4EV3zyWNoPa2TU8JGaUCcEGGF3KMMSEkYjg"
},
{
"controlKey": "6436f7db26ed58ee35c74ca283bea063a1fed2bcb0a1e7c3fc87f500eea77f29",
"path": "m/0'/1",
"extendedPrivateKey": "xprv9zBMrCRQTNmH5qNiyMmj1DMDTbLRxHAwTY5ca2HmdguM1opFLeC8z8kqkCd6QjjSeWmaui8fEYE1QNcC8mUfxVm6iwxCMXvXibZFSjsvZUj"
},
{
"controlKey": "6436f7db26ed58ee35c74ca283bea063a1fed2bcb0a1e7c3fc87f500eea77f29",
"path": "m/0'/1/2'",
"extendedPrivateKey": "xprv9zZ86emkmNgqvLzxJx7ohoFUsFBrBj7Nv98N6vmjsDe7d9seStePWBqLWdXbNfRRi2upCbX6snEtoPGn9NNsEE7RWXaxTXvguQeHMsT6AYK"
},
{
"controlKey": "6436f7db26ed58ee35c74ca283bea063a1fed2bcb0a1e7c3fc87f500eea77f29",
"path": "m/0'/1/2'/2",
"extendedPrivateKey": "xprvA3U4KwKaPGk4ES3tqwX4uecfZqqNUnGhsbfaWji9XBhJ4jb2mBGqUD5QLj6LcvndBtu3CdW7XqPAXia23QVA4NUMauTsXeyqsf7FuMmLazF"
},
{
"controlKey": "6436f7db26ed58ee35c74ca283bea063a1fed2bcb0a1e7c3fc87f500eea77f29",
"path": "m/0'/1/2'/2/1000000000",
"extendedPrivateKey": "xprvA4dAgiGBXfzxhUmacEbguNGvJhMhJ3gL6t6f5omuTiHHMNmgiNMmMFiMPnvUSjSS8bqjM5zYqRCi8ZPxpGB1355Bx4x8sRyW1e8BwqheFXT"
},
{
"controlKey": "fc90028b3ab1e467ddc7e6d6a4105f58bcec09c4e27c1d6f70b09846fd746e4a",
"path": "m/0/0/0"
},
{
"controlKey": "6436f7db26ed58ee35c74ca283bea063a1fed2bcb0a1e7c3fc87f500eea77f29",
"path": "m/0h/1/2h/2"
}
]
}
```
Anchorage Digital runs this same byte-parity check in continuous integration on every change to the reference code or the test vectors above.
## Use the key in a transfer
1. Call `GET /v2/wallets/{walletId}` for the source wallet and read `derivationPath` from the response.
2. Derive the child control key and hex-encode it (64 lowercase hex characters).
3. Include it when creating the transfer:
```bash theme={null}
curl "https://api.anchorage-staging.com/v2/transfers" \
--json @transfer.json \
-H "Api-Access-Key: $API_ACCESS_KEY" \
-H "Api-Signature: $API_SIGNATURE" \
-H "Api-Timestamp: $API_TIMESTAMP" \
-H "Api-Child-Control-Key: $CHILD_CONTROL_KEY"
```
The `Api-Child-Control-Key` header is required only for self-custody organizations initiating transfers through the API. The `Api-Signature` and `Api-Timestamp` headers carry the standard Ed25519 request signature that `POST /v2/transfers` always requires; see [Signing requests](/knowledge-base/porto/developers/request-signing) for how to compute them.
# Transfers and withdrawals
Source: https://docs.anchorage.com/knowledge-base/porto/developers/move-money/transfers-vs-withdrawals
Two approval models for moving assets out of Anchorage Digital.
You're viewing **Porto** developer documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/developers/setting-up)
Both transfers and withdrawals move assets out of—or between—your holdings. The difference is the approval model, and that choice drives the setup, the destinations you can reach, and the controls on each movement.
## Transfers
A transfer moves assets without quorum approval on each request, which suits recurring or high-frequency flows. Approval is front-loaded into one-time setup: an allowlisted destination and a permission group scoped to the operation. Transfers reach internal wallets and external destinations.
## Withdrawals
A withdrawal requires quorum approval on every request, giving you granular control over each movement through your vault policies. Because each withdrawal is approved individually, the destination doesn't need to be allowlisted in advance.
## Feature comparison
| | Internal transfer | External transfer | Withdrawal |
| :--------------------------------------------------------------- | :------------------------ | :----------------------------------------- | :--------------------------------------------------- |
| Quorum required (per request) | | | |
| Destination | Wallets you own | Allowlisted address or trusted destination | Any address, trusted destination, or internal wallet |
| Pre-allowlisted destination required | | | |
| Trusted destination bound to permission group | | Configurable | |
| Memo or tag inherited from trusted destination | n/a | | |
| Queued | Yes (up to 50 per source) | Yes | No (one at a time) |
| Deduct network fee from amount (`deductFeeFromAmountIfSameType`) | | | |
## Source and destination options
| Operation | Source | Destination |
| :---------------- | :------- | :-------------------------------------------- |
| Internal transfer | `WALLET` | `WALLET` |
| External transfer | `WALLET` | `ADDRESS` or `TRUSTED_DESTINATION` |
| Withdrawal | `WALLET` | `WALLET`, `ADDRESS`, or `TRUSTED_DESTINATION` |
Prefer `WALLET` over `VAULT`. When a `VAULT` is specified, the system selects the first-created wallet in the vault for the asset, even if that wallet has been archived. Use `VAULT` only when a single wallet per asset is maintained. The `VAULT` type will be deprecated in the future.
## When a transfer queues
Queuing is keyed to the **source wallet**—never the vault, and never the destination. A transfer is held as `QUEUED` only when another movement is already in flight from the same source wallet:
* A **withdrawal pending** from that source wallet holds subsequent transfers until the withdrawal is broadcast or cancelled.
* A **transfer in progress** from that source wallet holds additional transfers behind it; they appear in the activity log. Up to 50 transfers can be queued per source wallet.
Activity on the *destination* never queues a transfer. Sending from wallet A to wallet B doesn't queue just because wallet B has a pending withdrawal. For the per-asset and per-blockchain specifics, see [Crypto transfer](/knowledge-base/porto/developers/move-money/transfer/crypto).
Withdrawals themselves don't queue. If a withdrawal is already ongoing from a source wallet, a new withdrawal request from that wallet fails rather than waiting in line.
To keep quorum-pending withdrawals from blocking automated transfers, isolate withdrawals in a dedicated wallet. Transfers from your other wallets then run without waiting on withdrawal approvals.
## The same move, two ways
Moving 1 ETH to a destination you've allowlisted—first as a transfer (no per-request approval), then as a withdrawal (quorum on each request):
```json Transfer — POST /v2/transfers theme={null}
{
"source": { "id": "{source wallet ID}", "type": "WALLET" },
"destination": { "id": "{trusted destination ID}", "type": "TRUSTED_DESTINATION" },
"assetType": "ETH",
"amount": "1",
"idempotentId": "{unique ID}"
}
```
```json Withdrawal — POST /v2/transactions/withdrawal theme={null}
{
"source": { "id": "{source wallet ID}", "type": "WALLET" },
"destination": { "id": "{trusted destination ID}", "type": "TRUSTED_DESTINATION" },
"assetType": "ETH",
"amount": "1",
"idempotentId": "{unique ID}"
}
```
The transfer clears without a per-request approval because the destination and permission group were authorized up front; the withdrawal routes to quorum approval before it broadcasts. See [Crypto transfer](/knowledge-base/porto/developers/move-money/transfer/crypto) and [Crypto withdrawal](/knowledge-base/porto/developers/move-money/withdraw/crypto) for full payloads and fields.
## Which to use
Choose a **transfer** when you want automated, repeatable movement and you've pre-authorized the destination and permissions. Choose a **withdrawal** when you want a human quorum checkpoint on each movement, or you're sending to a one-off destination you don't want to allowlist.
For full API details, see [Crypto transfer](/knowledge-base/porto/developers/move-money/transfer/crypto) and [Crypto withdrawal](/knowledge-base/porto/developers/move-money/withdraw/crypto).
# Crypto withdrawal
Source: https://docs.anchorage.com/knowledge-base/porto/developers/move-money/withdraw/crypto
Move digital assets out of a wallet with quorum approval on every request.
You're viewing **Porto** developer documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/developers/setting-up)
A crypto withdrawal moves digital assets out of a wallet with quorum approval on every request. For the shared model, the approval workflow, status values, and fees, see [Transfers and withdrawals](/knowledge-base/porto/developers/move-money/transfers-vs-withdrawals). This page covers the crypto-specific payloads.
`POST /v2/transactions/withdrawal` requires the `Initiate withdrawals` permission and an Ed25519 request signature.
## Request
Withdraw to an external address directly, or to a destination you've allowlisted as a trusted destination:
```json External address theme={null}
{
"amount": "{quantity}",
"assetType": "{asset}",
"source": {
"id": "{source wallet ID}",
"type": "WALLET"
},
"destination": {
"id": "{external address}",
"type": "ADDRESS"
},
"description": "{description}"
}
```
```json Trusted destination theme={null}
{
"idempotentId": "{unique ID}",
"amount": "{quantity}",
"assetType": "{asset}",
"source": {
"id": "{source wallet ID}",
"type": "WALLET"
},
"destination": {
"id": "{trusted destination ID}",
"type": "TRUSTED_DESTINATION"
},
"description": "{description}"
}
```
### Fields
| Field | Description |
| :----------------- | :--------------------------------------------------------------------------------------------------------------------------- |
| `amount` | Quantity as a string, without units. |
| `assetType` | The asset to withdraw. List supported values via `GET /v2/asset-types`. |
| `source` | The wallet to withdraw from (`type: WALLET`). |
| `destination.type` | `ADDRESS` for an external address, `TRUSTED_DESTINATION` for an allowlisted destination, or `WALLET` for an internal wallet. |
| `description` | Optional context, visible in the iOS app and not published on-chain. |
| `idempotentId` | Optional client-provided unique ID for safe retries. |
For assets that use a memo or destination tag, the value is inherited automatically when you withdraw to a trusted destination—you don't provide `assetParameters` yourself.
### Response
A successful request returns `201` with a `withdrawalId`:
```json theme={null}
{
"data": {
"withdrawalId": "8696144cca28a634c05858d00e51191408498a7808a837fc4645b4b6997dde09"
}
}
```
Track status through the transactions API. See [Track movement status](/knowledge-base/porto/developers/move-money/operate/track-status).
## UTXO assets
For UTXO-based assets, Anchorage Digital exposes a single wallet-level address as the representative address and selects UTXOs randomly across the wallet's addresses to preserve privacy. Sub-UTXO balances remain visible on-chain.
## Troubleshooting
Withdrawals are not queued: a request fails if one is already ongoing for the source. Other request-level failures include an unknown asset, an amount that exceeds available funds (including fees), an invalid destination address, or a key without withdrawal permissions for the vault.
If a withdrawal fails when specified at the wallet or address level, try specifying the source at the vault level with a vault ID.
After quorum approval, a withdrawal can still fail at execution if there are insufficient funds for the network fee or there's a blockchain-level failure.
# Network & gas fees
Source: https://docs.anchorage.com/knowledge-base/porto/developers/network-gas-fees
How blockchain transaction fees work and how Anchorage Digital manages them.
You're viewing **Porto** developer documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/developers/setting-up)
On blockchains, each node is incentivized to provide processing power to add a new block by the promise of collecting a reward. One such reward is a network fee — paid per transaction in the network's native currency by the address wishing to execute the transaction.
These fees serve an important role:
* Network fees help pay for network security by rewarding the people who keep track of activities across the network.
* Network fees incentivize purposeful use of the network. Free transactions would make it trivial to spam the network with meaningless activity, threatening its stability.
* Fee calculation differs by blockchain — Anchorage Digital simplifies this by managing network fees on behalf of clients.
* On Ethereum, fees are called **gas fees**. On Bitcoin, they are simply called **transaction fees**.
For deeper background, see [Chapter 6 of the Bitcoin Whitepaper](https://bitcoin.org/bitcoin.pdf) and the [Gas and fees](https://ethereum.org/developers/docs/gas) article on Ethereum's website.
***
## Anchorage Digital fee requirements
For any blockchain interaction through Anchorage Digital:
* The wallet interacting with the blockchain must pay the transaction fees for that transaction.
* The wallet must hold enough balance to cover eventual transaction fees.
* Required balance is either:
* **Estimated** — for withdrawals, staking, and smart contract operations. Estimates are conservative to ensure sufficient funds remain at broadcast time.
* **Fixed** — referred to as the "Fee threshold" for transfers initiated through the API.
* The actual fee set at broadcast time is always based on a network fee estimate plus an overhedge.
***
## Transaction FeeThreshold (API only)
To ensure on-chain operations triggered by API have the highest probability of processing during times of high fees and market volatility, Anchorage Digital defines an internal `FeeThreshold` for each protocol.
This `FeeThreshold` is an internal "sufficient funds" check — not the actual fee charged. It ensures that when multiple transfers or operations are triggered from the same wallet, funds exist to process each transaction. Once this check passes, the transaction is processed on-chain and the actual fee is charged. If a transfer is queued, the transfer amount and `feeThreshold` are held and inaccessible to prevent double-spending.
If the wallet has insufficient funds, the API call returns an error.
The `FeeThreshold` is fixed and intentionally conservative. Actual fees at broadcast time may be higher or lower depending on network conditions. This does not apply to iOS or web operations.
***
## Gas limit
The **gas limit** specifies how many units of gas a user is willing to pay to get a transaction executed. Gas units represent the computational work required to execute the transaction — more complex interactions require more gas.
Examples:
* A simple ETH transfer requires exactly **21,000 gas units**.
* An ERC-20 transfer requires more.
* A smart contract swap requires substantially more.
Setting a gas limit below what's required causes the transaction to fail on-chain.
***
## Base fee
The **base fee** is set by the network to manage congestion. A transaction must offer at least the base fee to be eligible for inclusion in a block.
The base fee adjusts between blocks:
* Increases by **12.5%** if the previous block was more than half full.
* Decreases by **12.5%** if the previous block was below the threshold.
# Permission groups
Source: https://docs.anchorage.com/knowledge-base/porto/developers/permission-groups
Create permission groups and select the global and vault-level permissions each API key needs.
You're viewing **Porto** developer documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/developers/setting-up)
A permission group is a reusable rule set that defines what actions an API key can perform, scoped to a single vault or across multiple vaults. An API key's capabilities come from the group assigned to it, not the key itself, so the group is where you decide what an integration can do.
By default, Anchorage Digital vaults don't allow API access. To enable it, an administrator either creates a permission group with the permissions each vault needs, or creates a key using the default read-only group.
Any activity related to permission groups requires quorum approval, so changes stay in the hands of your trusted admins.
Set up multiple permission groups and create as many API keys as you need under each group.
Updates to a permission group propagate to all of its API keys. Deleting a group invalidates every key within it.
Each organization starts with a default read-only permission group, which you can modify at any time.
**Permission group segregation**
Most clients create a permission group per team or end-user group, with one key for each. For example:
* Admin permission group — full permissions
* Operations — limited to reading balances and internal transfers
* Accounting — read only
## How to create a permission group
From the homepage, select **Developers**, then **API 2.0** to access Anchorage Digital APIs, then select **Create new group**.
Give the permission group a name and select the appropriate global and vault-level permissions.
Optionally add a comment, then select **Endorse** to create the group. Follow the prompts to submit biometric approval through the mobile app — quorum approval is required. After quorum is met, Anchorage Digital reviews the group for approval.
To edit or delete a permission group, select the three-dot menu next to the group details. Edits and deletions also require quorum approval.
## Permission levels
When you create a permission group, your selections determine which APIs the associated keys can call. There are two levels of vault permissions.
### Global permissions
Global permissions sit across all of your vaults, not just one. If a key has the global **Initiate withdrawals** permission, it can initiate a withdrawal from any of your vaults. Withdrawals still require quorum approval.
### Vault-level permissions
Vault-level permissions are specific to a single vault. If a key has vault-level **Internal Transfer** permissions, it can initiate a transfer only from that source vault, or the wallets within it.
### All-vaults
The all-vaults option lets all current and future vaults inherit a permission. Even if a vault changes names or moves to a different account, any key keeps the permission.
## Permissions reference
| Category | Permission | Description |
| :---------- | :-------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------- |
| Global | Initiate withdrawals | Initiate withdrawals to external destinations. All withdrawals require quorum approval through the Anchorage Digital mobile app. |
| Global | Configure webhooks | Configure and manage webhooks via REST API. |
| Global | Initiate staking and unstaking | Initiate staking and unstaking operations from wallets. |
| Global | Manage trusted destinations | Create and manage trusted destinations. |
| Vault-level | Read | Read balances and transactions for the wallets within this vault. |
| Vault-level | Create address | Create wallets and addresses within a vault. |
| Vault-level | Transfer funds — within Anchorage Digital | Transfer funds from that source vault. |
| Vault-level | Transfer funds — outside of Anchorage Digital | Transfer funds from that source vault. |
Once your group is approved, [create an API key](/knowledge-base/porto/developers/api-keys) and assign it to the group.
# Signing requests
Source: https://docs.anchorage.com/knowledge-base/porto/developers/request-signing
Create Ed25519 signatures for sensitive Anchorage Digital API requests.
You're viewing **Porto** developer documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/developers/setting-up)
Certain Anchorage endpoints require an [Ed25519 signature](https://en.wikipedia.org/wiki/EdDSA#Ed25519) in the request headers alongside the API key. Signatures are optional unless explicitly required, but are encouraged for all requests for maximum security. The `Api-Signature` is valid for 60 seconds.
## Signature input
Create the signature by concatenating these values:
```text theme={null}
timestamp + uppercase HTTP method + request path including query + request body
```
For requests without a body, omit the body from the signature input. For requests with a JSON body, sign the **exact bytes sent over the wire** — that is, `JSON.stringify(body)` with no extra whitespace. Any difference (stray spaces, trailing newlines, key reordering) will produce a signature the server rejects.
| Value | Notes |
| -------------- | ------------------------------------------------------------------------------------------ |
| `timestamp` | Seconds since the Unix Epoch in UTC. It must be within one minute of the API service time. |
| `method` | Uppercase HTTP method, such as `GET`, `POST`, or `DELETE`. |
| `request path` | Path and query string, such as `/v2/transfers?foo=bar&baz=bang`. |
| `body` | `JSON.stringify(body)` for requests that include one. Empty for `GET`. |
## Sign a request
```java theme={null}
package com.anchorage.api.client;
import okio.Buffer;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
import org.bouncycastle.crypto.CryptoException;
import org.bouncycastle.crypto.Signer;
import org.bouncycastle.crypto.params.Ed25519PrivateKeyParameters;
import org.bouncycastle.crypto.signers.Ed25519Signer;
import org.json.JSONObject;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
/**
* A sample java API client to connect to Anchorage API v2
*
* Required dependencies:
* org.json:json:20210307
* org.bouncycastle:bcpkix-jdk15on:1.69
* commons-codec:commons-codec:1.15
* com.squareup.okio:okio:1.9.0
*/
public class RestClientWithSigning {
private RestTemplate restTemplate;
public static void main(String[] args){
RestClientWithSigning api = new RestClientWithSigning();
api.init();
api.apiCall();
}
private void init(){
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
factory.setConnectTimeout(2000);
factory.setReadTimeout(2000);
restTemplate = new RestTemplate(factory);
}
private void apiCall() {
try {
String url = "https://api.anchorage-staging.com/v2/transfers";
String body = createRequestBody();
HttpEntity request = new HttpEntity<>(body, createHeaders("/v2/transfers", HttpMethod.POST, body));
ResponseEntity responseEntity = restTemplate.exchange(url, HttpMethod.POST, request, String.class);
if (responseEntity != null && HttpStatus.CREATED == responseEntity.getStatusCode()) {
System.out.println(String.format("Getting data from ( %s ) response: %s", url, responseEntity.getBody()));
}
} catch (Exception e) {
e.printStackTrace();
}
}
private String createRequestBody(){
JSONObject source = new JSONObject();
source.put("id", "1c920f4241b78a1d483a29f3c24b6c4c");
source.put("type", "VAULT");
JSONObject destination = new JSONObject();
destination.put("id", "55e89d4a644d736b01533a2ea9b32a20");
destination.put("type", "VAULT");
JSONObject body = new JSONObject();
body.put("source", source);
body.put("assetType", "ETH");
body.put("destination", destination);
body.put("amount", "1000.00000000");
return body.toString();
}
private HttpHeaders createHeaders(String requestPath, HttpMethod httpmethod, String body) throws DecoderException, CryptoException {
String api_key = "your API Key";
String signing_key_hex = "Your signing key";
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.set("Api-Access-Key", api_key);
String timestamp = String.valueOf(Instant.now().getEpochSecond());
byte[] toSign = decodeMessage(timestamp, httpmethod, requestPath, body);
String signature = bc_sign(Hex.decodeHex(signing_key_hex), toSign);
headers.add("Api-Signature", signature);
headers.add("Api-Timestamp", timestamp);
return headers;
}
private byte[] decodeMessage(String timestamp, HttpMethod httpmethod, String url_path, String body){
Buffer buffer = new Buffer();
buffer.write(timestamp.getBytes(StandardCharsets.UTF_8))
.write(httpmethod.name().getBytes(StandardCharsets.UTF_8))
.write(url_path.getBytes(StandardCharsets.UTF_8))
.write(body.getBytes(StandardCharsets.UTF_8));
return buffer.readByteArray();
}
private String bc_sign(byte[] signing_key, byte[] toSign) throws CryptoException {
Ed25519PrivateKeyParameters privateKeyParameters = new Ed25519PrivateKeyParameters(signing_key);
Signer signer = new Ed25519Signer();
signer.init(true, privateKeyParameters);
signer.update(toSign, 0, toSign.length);
return Hex.encodeHexString(signer.generateSignature());
}
}
```
```csharp theme={null}
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using Sodium;
// Dependencies: Sodium.Core 1.3.1
// Replace privateKey, publicKey, and Api-Access-Key with your keys
namespace WebAPIClient
{
class Program
{
private static readonly HttpClient client = new HttpClient();
static async Task Main(string[] args)
{
await ProcessAnchorageAPISign();
}
private static async Task
```ruby theme={null}
require "ed25519"
require "net/http"
require "time"
def hex_to_bin(s)
[s].pack('H*')
end
def bin_to_hex(s)
s.unpack('H*').first
end
private_key_seed_hex = '0101010101010101010101010101010101010101010101010101010101010101'
public_key_hex = '8a88e3dd7409f195fd52db2d3cba5d72ca6709bf1d94121bf3748801b40f6f5c'
key_pair_hex = private_key_seed_hex + public_key_hex
key_pair = hex_to_bin(key_pair_hex)
signing_key = Ed25519::SigningKey.from_keypair(key_pair)
timestamp = '1577880000' # Time.now.to_i.to_s
req = Net::HTTP::Post.new('/v2/transfers?foo=bar&baz=bang')
req.body = '{"source": {"id": "1c920f4241b78a1d483a29f3c24b6c4c", "type": "VAULT"},
"assetType": "ETH", "destination": {"id": "55e89d4a644d736b01533a2ea9b32a20", "type": "VAULT"}, "amount": "1000.00000000"}'
signature = signing_key.sign(timestamp + req.method + req.path + req.body)
req['Api-Access-Key'] = 'YOUR_ACCESS_KEY'
req['Api-Timestamp'] = timestamp
req['Api-Signature'] = bin_to_hex(signature)
puts bin_to_hex(signature)
```
```python theme={null}
import time
import requests
from nacl import signing
class AnchorageAuth(requests.auth.AuthBase):
ACCESS_KEY_HEADER = "Api-Access-Key"
SIGNATURE_HEADER = "Api-Signature"
TIMESTAMP_HEADER = "Api-Timestamp"
def __init__(self, access_key: str, signing_key_seed: bytes):
self.access_key = access_key
self.signing_key = signing.SigningKey(signing_key_seed)
def __call__(self, request: requests.PreparedRequest):
request.headers[self.ACCESS_KEY_HEADER] = self.access_key
timestamp = str(int(time.time()))
method = request.method.upper() if request.method else "GET"
body = request.body or b""
if isinstance(body, str):
body = body.encode("utf-8")
message = b"".join([
timestamp.encode("utf-8"),
method.encode("utf-8"),
request.path_url.encode("utf-8"),
body,
])
request.headers[self.SIGNATURE_HEADER] = self.signing_key.sign(message).signature.hex()
request.headers[self.TIMESTAMP_HEADER] = timestamp
return request
```
```js theme={null}
const { sign } = require("@noble/ed25519");
const axios = require("axios");
class AnchorageClient {
constructor(accessKey, signingKeySeed) {
this.accessKey = accessKey;
this.signingKeySeed = signingKeySeed; // 32-byte hex seed
this.basePath = "https://api.anchorage-staging.com";
}
async sendSignedRequest(method, endpoint, body) {
const timestamp = Math.floor(Date.now() / 1000);
const serializedBody = body ? JSON.stringify(body) : "";
const signatureInput = `${timestamp}${method}${endpoint}${serializedBody}`;
const messageHex = Buffer.from(signatureInput, "utf8").toString("hex");
const signature = await sign(messageHex, this.signingKeySeed);
const signatureHex = Buffer.from(signature).toString("hex");
return axios({
method,
url: this.basePath + endpoint,
data: body,
headers: {
"Api-Access-Key": this.accessKey,
"Api-Signature": signatureHex,
"Api-Timestamp": String(timestamp),
"Content-Type": "application/json",
},
}).then((res) => res.data);
}
}
// Example: create a transfer
(async () => {
const client = new AnchorageClient("YOUR_ACCESS_KEY", "YOUR_SIGNING_KEY_SEED");
const transfer = await client.sendSignedRequest("POST", "/v2/transfers", {
source: { id: "1c920f4241b78a1d483a29f3c24b6c4c", type: "VAULT" },
assetType: "ETH",
destination: { id: "55e89d4a644d736b01533a2ea9b32a20", type: "VAULT" },
amount: "1000.00000000",
});
})();
```
`JSON.stringify(body)` produces the same compact bytes the server signs against, so you don't need to pre-serialize the request manually. The live signer above applies the same canonicalization to anything you paste into the body field.
# Setting up
Source: https://docs.anchorage.com/knowledge-base/porto/developers/setting-up
Set up the permission groups, keys, and signatures you need to call the Anchorage Digital API.
The Anchorage Digital API lets you automate custody, transfers, and reporting while staying inside the same security model that protects your assets. Every request runs over HTTPS and is governed by the permission group you assign to a key, so you control exactly what each integration can do.
You're viewing **Porto** developer documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/developers/setting-up)
This section walks you through setup end to end: creating the permission groups and keys you need, and signing sensitive calls.
Prefer to build with an AI assistant? Connect these docs to your AI tool and start from ready-made prompts. See [Build with AI](/knowledge-base/porto/build-with-ai/overview).
## What you can build
Generate reports, build financial dashboards, and view all digital assets in custody.
Download crypto balances, including all transactions, and store data for processing and reconciliation.
Stay current on key activities by integrating with [webhooks](/knowledge-base/porto/developers/webhooks/webhooks-configure).
## Set up your access
Complete these steps in order. The first two require quorum approval, so plan for your approvers to be available.
Define which vaults a key can access and what operations it can perform.
Generate an access key and tie it to a permission group.
Add an Ed25519 signature to endpoints that require one.
Only administrators can create and manage API keys and permission groups.
Ready to make your first request? Follow [Send your first API call](/knowledge-base/porto/api-reference/introduction#send-your-first-api-call).
# SOL
Source: https://docs.anchorage.com/knowledge-base/porto/developers/staking/sol-staking
Stake and unstake SOL via API.
You're viewing **Porto** developer documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/developers/setting-up)
# Overview
### Key concepts
* **Minimum stake:** 2 SOL.
* **Validator selection:** provide either a validator `address` or a `providerName`.
* Provide **one or the other**, not both.
* **Multiple stake requests:** staking multiple times to the same validator address will create multiple `stakingPositionId` values.
* **Unstake timing:** unstake requires about **one epoch (\~2–3 days)** to complete.
* **Collect timing and stake-account reserve:** to maximize rewards and avoid unexpected stake-account closure:
* Prefer waiting **1 epoch after an unstake completes** before collecting, *or*
* Leave a minimum reserve of **2,282,880 lamports (0.00228288 SOL)** in the `stakingPositionId` to prevent the stake account from being destroyed.
### Endpoint summary
* **[Stake](/knowledge-base/api-reference/endpoints/transactions/create-stake):** `POST /v2/transactions/stake`
* **[Unstake](/knowledge-base/api-reference/endpoints/transactions/create-unstake):** `POST /v2/transactions/unstake`
* **[Collect (SOL-specific)](/knowledge-base/api-reference/endpoints/transactions/collect):** `POST /v2/transactions/collect`
* **[Get staking positions](https://developers.anchorage.com/reference/getwalletpositions):** `GET /v2/wallets/{walletId}/staking/positions`
* **[Get staking rewards](https://developers.anchorage.com/reference/getwalletrewards):** `GET /v2/wallets/{walletId}/staking/rewards`
* **[List available validators](https://developers.anchorage.com/reference/getdelegationaddresses):** `GET /v2/delegation-addresses/{assetType}`
# Workflows
### Stake (Solana)
**Endpoint**
`POST /v2/transactions/stake`
#### Request rules
* `assetType` must be `"SOL"`.
* `amount` must be at least `"2"`.
* Include `parameters` with **either**:
* `address` (validator public identifier), **or**
* `providerName` (provider name)
#### Example: Stake using validator address
```json theme={null}
{
"source": {
"type": "WALLET",
"id": "1c920f4241b78a1d483a29f3c24b6c4c"
},
"amount": "5",
"assetType": "SOL",
"description": "Internal 9876543210",
"idempotentId": "9876543210",
"parameters": {
"address": "FuS3FPfJDKSNot99ECLXtp3rueq36hMNStJkPJwWodLh"
}
}
```
#### Example: Stake using provider name
```json theme={null}
{
"source": {
"type": "WALLET",
"id": "1c920f4241b78a1d483a29f3c24b6c4c"
},
"amount": "5",
"assetType": "SOL",
"description": "Internal 9876543210",
"idempotentId": "9876543211",
"parameters": {
"providerName": "figment"
}
}
```
#### Response
A successful request returns **201 Created** with a transaction id.
***
### Unstake (Solana)
**Endpoint**
`POST /v2/transactions/unstake`
#### Request rules
* `stakingPositionId` and `amount` are required.
* After the unstake completes (about \~1 epoch), funds are **inactive** but not yet available for use.
* Use the **Collect** endpoint (below) to move inactive SOL back to the wallet.
#### Example: Unstake
```json theme={null}
{
"source": {
"type": "WALLET",
"id": "1c920f4241b78a1d483a29f3c24b6c4c"
},
"amount": "5",
"assetType": "SOL",
"idempotentId": "123456789",
"description": "Unstake 5 SOL",
"stakingPositionId": "FuS3FPfJDKSNot99ECLXtp3rueq36hMNStJkPJwWodLh"
}
```
#### Response
A successful request returns **201 Created** with a transaction id.
***
### Collect (Solana-specific)
The collect action moves **inactive** SOL from a stake account back to the wallet's **available** balance.
**Endpoint**
`POST /v2/transactions/collect`
#### Request rules
* `stakingPositionId` is required.
* `amount` is required.
* `assetType` must be `"SOL"`.
#### Example: Collect
```json theme={null}
{
"stakingPositionId": "FuS3FPfJDKSNot99ECLXtp3rueq36hMNStJkPJwWodLh",
"amount": "2",
"assetType": "SOL"
}
```
#### Possible failure reasons
* **400 Invalid request**: unsupported `assetType`, not enough available balance.
* **404 Not found**: staking position not found.
### Get staking positions
This endpoint retrieves the staking positions (stake accounts) associated with a wallet.
**Endpoint**
`GET /v2/wallets/{walletId}/staking/positions`
#### Expected behavior
* Accepts `SOL` as a valid asset type to retrieve positions.
* Returns SOL staking positions, including `stakingPositionId` values.
### Get staking rewards
This endpoint is used to query rewards generated by staking and assigned to a wallet.
**Endpoint**
`GET /v2/wallets/{walletId}/staking/rewards`
#### Expected behavior
* Accepts `SOL` as a valid asset type.
* Includes `address` as an optional filtering argument.
### List wallet balances
This endpoint retrieves wallet balances for either a single wallet or all wallets in a vault.
**Endpoints**
* [List all wallets for all vaults](https://developers.anchorage.com/reference/getwallets)
#### Expected behavior
* The response includes a list of balance types per wallet.
* `stakedBalance` reflects SOL delegated to validators.
```json theme={null}
{
"data": {
"walletId": "3d293c0d64c703023692216e9b4f5280",
"walletName": "Solana Mainnet - Wallet 1",
"depositAddress": {
"address": "5oNDL3swdJJF1g9DzJiZ4ynHXgszjAEpUkxVYejchzrY",
"addressId": "a33f83d96ca95cac000a344aa478a8b8",
"addressSignaturePayload": "7b225465787441646472657373223a22356f4e444c337377644a4a46316739447a4a695a34796e485867737a6a414570556b785659656a63687a7259227d",
"signature": "1642000aa9cca8e8610981aefbdb204b361c9dca3fa067b88fdacfba7a0f620d721378a33f4bbadad3923e633a4d712646d1e8e314e9fcb4aa4102c0581f6503"
},
"assets": [
{
"assetType": "SOL",
"availableBalance": {
"quantity": "100.00000000",
"assetType": "SOL",
"currentPrice": "150.25",
"currentUSDValue": "15025.00"
},
"totalBalance": {
"quantity": "603.00000000",
"assetType": "SOL",
"currentPrice": "150.25",
"currentUSDValue": "90600.75"
},
"stakedBalance": {
"quantity": "500.50000000",
"assetType": "SOL",
"currentPrice": "150.25",
"currentUSDValue": "75200.13"
},
"unclaimedBalance": {
"quantity": "2.50000000",
"assetType": "SOL",
"currentPrice": "150.25",
"currentUSDValue": "375.63"
}
}
],
"vaultId": "1c920f4241b78a1d483a29f3c24b6c4c",
"vaultName": "Long Hold Vault",
"isDefault": true,
"isArchived": false,
"networkId": "SOL",
"type": "WALLET"
}
}
```
### List available validators (delegation addresses)
A new endpoint is introduced to retrieve the list of available validators for delegation.
**Endpoint**
`GET /v2/delegation-addresses/{assetType}`
#### Request parameters
* `assetType`: must be `SOL` for Solana validators.
* `limit`: pagination size.
* `afterId`: pagination cursor.
#### Example request
`GET /v2/delegation-addresses/SOL?limit=10&afterId=XXXXXX`
#### Example response
```json theme={null}
{
"data": [
{
"address": "FuS3FPfJDKSNot99ECLXtp3rueq36hMNStJkPJwWodLh",
"ownerAddress": "",
"destination": "",
"name": "Delegator name",
"description": "some description",
"anchorageValidator": false
}
],
"page": {
"next": "XXXXXY"
}
}
```
### Common pitfalls
* For `POST /v2/transactions/stake`, provide **either** `parameters.address` **or** `parameters.providerName` (not both).
* Do not expect unstaked SOL to be immediately available. Plan for **epoch timing**, then call **collect**.
* If you want to keep the stake account alive (for rewards or operational reasons), leave the **minimum reserve** in the stake account when collecting.
# Overview
Source: https://docs.anchorage.com/knowledge-base/porto/developers/staking/staking-overview
Get started with staking operations via the Anchorage Digital API.
You're viewing **Porto** developer documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/developers/setting-up)
# Getting started with staking API
To get started, ensure you have the correct [API permission group](/knowledge-base/porto/developers/permission-groups), API key, and a sufficiently funded wallet.
End-to-end staking via API is available for **SOL** only. Stake other assets in the iOS app or web dashboard.
1. **Create the API permission group, including the following permissions:**
1. Read vaults.
2. Initiate staking and unstaking.
2. **Quorum approval**
1. Admins must confirm the operation via quorum on an iOS device.
3. **Create an API key with the staking permission group**
1. Once you've created your permission group, create an API key tied to this permission group to use for staking operations.
2. See [API permission groups and API keys](/knowledge-base/porto/developers/permission-groups).
# Configure webhooks
Source: https://docs.anchorage.com/knowledge-base/porto/developers/webhooks/webhooks-configure
Set up webhook endpoints, subscriptions, and signature validation for event-driven notifications.
You're viewing **Porto** developer documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/developers/setting-up)
Webhooks are enabled by Anchorage Digital upon request. Notify your integration point of contact to enable webhooks for your organization.
## Managing webhooks from the dashboard
Step-by-step instructions and screenshots for creating and managing webhooks in the web dashboard are coming soon.
For payload schema, signature validation, and code samples for a programmatic setup, see the API instructions below.
## Subscribing to webhooks via API
### API permission group configuration
Update your permission group to include the global permission **Configure webhooks**. Either create a new permission group or edit an existing one.
See [Permission Groups](/knowledge-base/porto/developers/permission-groups) for instructions.
### Webhook validation key
The webhook validation key is a hex-encoded Ed25519 public key used to verify the `Api-Signature` header on incoming notifications. Retrieve it via the API and keep this value tamper-proof.
* [Read webhook validation key](/knowledge-base/api-reference/v2/webhook-notifications/get-webhook-validation-key)
The API returns the key as a hex string (64 characters representing 32 bytes). This is the same format used in the code samples below.
### Idempotency with `message_id`
Each message includes a `message_id` — treat it as an idempotent ID to detect duplicate deliveries. Also use `timestamp` to validate event freshness. For details on retry behavior, timeout requirements, and best practices, see [Delivery and reliability](/knowledge-base/porto/developers/webhooks/webhooks-delivery).
### Webhook schema
| Field | Description |
| :----------- | :-------------------------------------------------------------------------------------------------- |
| `payload` | Base64-encoded payload containing the relevant `transactionId` or other IDs depending on event type |
| `timestamp` | Unix timestamp of when the message was sent |
| `message_id` | Unique ID for this event message — use as idempotent ID |
| `event_type` | The event topic and name for the subscription |
```json Schema theme={null}
{
"payload": "[]byte",
"timestamp": "int64",
"message_id": "string",
"event_type": "string"
}
```
### Create a webhook endpoint
* [Create webhook endpoint](/knowledge-base/api-reference/v2/webhook-notifications/create-webhook-endpoint)
* [List webhook endpoints](/knowledge-base/api-reference/v2/webhook-notifications/list-webhook-endpoint)
### List available event types
List the full set of event types configured for your organization before creating subscriptions.
* [Get webhook event types](/knowledge-base/api-reference/v2/webhook-notifications/list-webhook-event-types)
```json Example response theme={null}
{
"data": [
{
"description": "Notification of a successful withdrawal completed on-chain",
"id": "withdrawal.completed"
},
{
"description": "Notification of a failed transfer",
"id": "transfer.failed"
},
{
"description": "Notification of successful completion of deposit attribution",
"id": "deposit.attributed"
},
{
"description": "Notification of a successful withdrawal initiated but still pending quorum approval and/or risk review",
"id": "withdrawal.initiated"
},
{
"description": "Notification of a successful transfer that is now completed",
"id": "transfer.completed"
},
{
"description": "Notification of a new deposit pending attribution",
"id": "deposit.pending-attribution"
},
{
"description": "Notification of a failed withdrawal",
"id": "withdrawal.failed"
},
{
"description": "Notification of a transfer that has successfully been initiated",
"id": "transfer.initiated"
}
],
"page": {
"next": null
}
}
```
### Create webhook subscriptions
Subscribe an endpoint to one or more event types. A notification is sent to all subscribed endpoints each time the event fires.
* [Create webhook subscriptions](/knowledge-base/api-reference/v2/webhook-notifications/create-webhook-subscriptions)
* [List webhook subscriptions](/knowledge-base/api-reference/v2/webhook-notifications/list-webhook-endpoint-subscriptions)
### Validate the signature and decode the payload
Every webhook request includes an `Api-Signature` header containing a hex-encoded Ed25519 signature. The signature is computed over the **raw HTTP request body** exactly as received — no timestamp prefix, no additional framing.
To verify:
1. Hex-decode the `Api-Signature` header value to get the raw signature bytes.
2. Verify the signature against the raw request body using the Ed25519 validation key.
3. Base64-decode the `payload` field inside the JSON body to get the event data.
* [Base64 decode tool](https://www.base64decode.org/)
* [Ed25519 signature verification tool](https://cyphr.me/ed25519_tool/ed.html)
```javascript JavaScript theme={null}
import * as ed from '@noble/ed25519';
const pubKey = 'c14b7f3da18abb17b7304f925a68b18c1ea0dad6663b6b54cb67a737ecb77cd0';
function toHex(str) {
return Array.from(new TextEncoder().encode(str))
.map((b) => b.toString(16).padStart(2, '0'))
.join('');
}
const message = `...`; // raw message body
const signature = '...'; // Api-Signature header value
const isValid = await ed.verifyAsync(signature, toHex(message), pubKey);
console.log("Is valid: ", isValid);
console.log("Payload: ", atob(JSON.parse(message).payload));
```
```python Python theme={null}
from http.server import BaseHTTPRequestHandler, HTTPServer
from nacl.exceptions import BadSignatureError
from nacl.encoding import HexEncoder
from nacl.signing import VerifyKey
import base64
import json
publicKey = VerifyKey(
"c14b7f3da18abb17b7304f925a68b18c1ea0dad6663b6b54cb67a737ecb77cd0",
encoder=HexEncoder
)
class MyServer(BaseHTTPRequestHandler):
def do_POST(self):
signature = HexEncoder.decode(self.headers.get("Api-Signature"))
content_len = int(self.headers.get('Content-Length'))
message = self.rfile.read(content_len)
try:
publicKey.verify(message, signature)
except BadSignatureError:
print("Invalid signature")
payload = base64.b64decode(
json.loads(message)["payload"].encode('utf-8')
).decode('utf-8')
print("Payload", payload)
self.send_response(200)
self.end_headers()
```
***
## Payload encryption (optional)
By default, webhook payloads are sent as plaintext JSON signed with the `Api-Signature` header. For an additional layer of security, you can enable ECIES payload encryption by registering a secp256k1 public key with your endpoint.
### How it works
When you register an endpoint with a `public_key`, Anchorage Digital encrypts the entire webhook payload using ECIES (Elliptic Curve Integrated Encryption Scheme) with your secp256k1 public key before delivery. The encrypted request differs from a standard webhook in two ways:
| | Standard webhook | Encrypted webhook |
| :-------------- | :--------------------------- | :---------------------------- |
| `Content-Type` | `application/json` | `application/octet-stream` |
| Body | JSON (`WebhookMessage`) | ECIES ciphertext |
| `Api-Signature` | Signature over the JSON body | Signature over the ciphertext |
To process an encrypted webhook:
1. Verify the `Api-Signature` against the raw request body (the ciphertext).
2. Decrypt the body using your secp256k1 private key to recover the JSON `WebhookMessage`.
3. Base64-decode the `payload` field inside the decrypted JSON.
### Key format
The `public_key` field must be a **PEM-encoded secp256k1 public key**. This is different from the validation key, which is returned as a hex-encoded Ed25519 key.
| Key | Format | Purpose |
| :------------------ | :------------------------------------------------------- | :----------------------------- |
| Validation key | Hex-encoded Ed25519 (from `GET /webhook/validation-key`) | Verify `Api-Signature` headers |
| Endpoint public key | PEM-encoded secp256k1 (provided by you) | Encrypt webhook payloads |
To enable encryption, include the `public_key` field when [creating](/knowledge-base/api-reference/v2/webhook-notifications/create-webhook-endpoint) or [updating](/knowledge-base/api-reference/v2/webhook-notifications/update-webhook-endpoint) your webhook endpoint. To disable encryption, remove the `public_key` from the endpoint configuration.
***
## Manage endpoints and subscriptions
Once configured, update or cancel webhook endpoints and subscriptions as needed.
* [Get webhook endpoint config](/knowledge-base/api-reference/v2/webhook-notifications/get-webhook-endpoint-config)
* [Update webhook endpoint](/knowledge-base/api-reference/v2/webhook-notifications/update-webhook-endpoint)
* [Cancel webhook subscription](/knowledge-base/api-reference/v2/webhook-notifications/cancel-webhook-subscription)
***
## Additional resources
* [Webhook standards](https://webhooks.fyi/learn-more/standards)
* [Webhook consumer best practices](https://webhooks.fyi/best-practices/webhook-consumers)
# Delivery and reliability
Source: https://docs.anchorage.com/knowledge-base/porto/developers/webhooks/webhooks-delivery
Understand retry behavior, delivery guarantees, timeout requirements, and best practices for consuming webhooks.
You're viewing **Porto** developer documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/developers/setting-up)
Anchorage Digital webhooks use at-least-once delivery. Every event notification is retried until your endpoint confirms receipt with a successful response, or until the retry limit is reached. Because webhooks carry money-movement events, we recommend designing your consumer for reliability from the start.
## Delivery guarantees
Anchorage Digital guarantees **at-least-once delivery** for every webhook event. This means:
* Every event fires at least one delivery attempt to each subscribed endpoint.
* The same event may be delivered more than once. Use the `message_id` field to deduplicate.
* Events are not guaranteed to arrive in the order they occurred. Your consumer should handle out-of-order delivery gracefully.
## Retry behavior
We redeliver on any non-2xx response, including 5xx errors, connection failures, and timeouts. Successful delivery requires an HTTP 2xx response from your endpoint.
| Parameter | Value |
| :----------------- | :---------------------------------------------------- |
| Retry attempts | Up to 50 per event |
| Backoff strategy | Exponential, starting at 1 second |
| Maximum interval | 2 hours between attempts |
| Total retry window | 75+ hours |
| Final status | Permanently canceled after all attempts are exhausted |
After all retry attempts are exhausted, the notification is permanently canceled and won't be redelivered. The endpoint registration stays active and continues to receive future events.
We don't auto-disable endpoints after consecutive failures. Failed notifications are canceled individually after retry exhaustion, but your endpoint configuration and subscriptions remain unchanged.
## Consumer endpoint requirements
Your endpoint must meet these requirements to receive webhook notifications reliably.
| Requirement | Detail |
| :--------------- | :---------------------------------- |
| Response timeout | Respond within **5 seconds** |
| Success response | Return any HTTP **2xx** status code |
| HTTPS | Endpoint URL must use HTTPS |
Acknowledge the webhook immediately and process the event asynchronously. This keeps your response time well within the 5-second window and prevents retries caused by slow processing.
## Idempotency and deduplication
Each webhook message includes a unique `message_id`. Because at-least-once delivery means duplicates are possible, treat `message_id` as an idempotent key:
1. Store each `message_id` you process.
2. Before processing a new message, check whether you've already handled that `message_id`.
3. Skip duplicate messages to avoid double-processing.
The `message_id` is a UUID assigned when the event is created. It stays the same across all delivery attempts for that event — if the same message is retried, you'll see the same `message_id`. Each distinct event produces exactly one `message_id`, so you won't receive the same event under different IDs.
The `timestamp` field reflects when each delivery attempt is made, not when the event originally occurred. This means the `timestamp` may differ between retries of the same `message_id`. Use `timestamp` to validate event freshness, but use `message_id` for deduplication.
## Handling out-of-order events
Webhook events may arrive out of order. For example, a `withdrawal.completed` event could arrive before the corresponding `withdrawal.initiated` event if delivery of the first event was delayed by retries.
To handle this:
* Use the `timestamp` field to determine the actual sequence of events.
* Design your state machine to accept transitions from any prior state, not just the immediately preceding one.
* When correlating events to transactions, fetch the current transaction status from the API as the source of truth rather than relying solely on webhook event order.
For details on correlating webhook events to transactions, see [Track transaction status](/knowledge-base/porto/developers/move-money/operate/track-status).
## Monitoring and failure notifications
We don't send automatic alerts when individual notifications exhaust their retries. Delivery status is tracked internally for incident investigation.
To monitor webhook health on your side:
* Log every incoming webhook and its `message_id`.
* Track the gap between the event `timestamp` and your receipt time to detect delivery delays.
* Periodically reconcile webhook events against API transaction data to catch any missed notifications. Use [List transactions](/knowledge-base/api-reference/v2/transactions/list-transactions) to fetch the latest state.
## Validation key
The webhook validation key is a hex-encoded Ed25519 public key used to verify the `Api-Signature` header. You can retrieve it at any time via the [Get webhook validation key](/knowledge-base/api-reference/v2/webhook-notifications/get-webhook-validation-key) endpoint.
There is no automatic key rotation. If a key change is required, Anchorage Digital will coordinate directly with affected clients. There is no `key-id` header — the current validation key is always the correct one to use for signature verification.
The validation key (hex-encoded Ed25519) is a different key from the optional endpoint encryption key (PEM-encoded secp256k1). For details on payload encryption, see [Payload encryption](/knowledge-base/porto/developers/webhooks/webhooks-configure#payload-encryption-optional).
## Best practices
* **Respond fast, process later.** Return a 2xx response as soon as you receive the webhook, then process the payload asynchronously. This avoids unnecessary retries.
* **Deduplicate with `message_id`.** At-least-once delivery means you may receive the same event more than once.
* **Validate signatures first.** Always [verify the `Api-Signature` header](/knowledge-base/porto/developers/webhooks/webhooks-configure#validate-the-signature-and-decode-the-payload) before processing any webhook payload.
* **Handle unknown event types gracefully.** New event types may be added over time. Your consumer should ignore unrecognized `event_type` values rather than failing.
* **Reconcile periodically.** Don't rely on webhooks as your only data source for critical flows. Use the API to periodically verify transaction states, especially for money-movement operations.
# Overview
Source: https://docs.anchorage.com/knowledge-base/porto/developers/webhooks/webhooks-overview
Receive event-driven notifications for operations and transactions across your organization.
You're viewing **Porto** developer documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/developers/setting-up)
The Anchorage Digital Webhooks API delivers event-driven notifications for your organization's operations and transactions. Event notifications are configurable by endpoint and by event type.
For details on retry behavior, delivery guarantees, and consumer requirements, see [Delivery and reliability](/knowledge-base/porto/developers/webhooks/webhooks-delivery).
## Supported events
Not all webhook events appear in every account, some are restricted to specific use cases.
### transfer
**`transfer.initiated`** Payload: `transactionId`, [`details`](#transaction-lifecycle-transfers-and-withdrawals)
Transfer initiated. Fires multiple times as the transfer advances — see [Transaction lifecycle](#transaction-lifecycle-transfers-and-withdrawals).
**`transfer.completed`** Payload: `transactionId`, [`details`](#transaction-lifecycle-transfers-and-withdrawals)
Transfer successfully completed.
**`transfer.failed`** Payload: `transactionId`, [`details`](#failure-reasons)
Transfer failed. See [Failure reasons](#failure-reasons).
### withdrawal
**`withdrawal.initiated`** Payload: `transactionId`, [`details`](#transaction-lifecycle-transfers-and-withdrawals)
Withdrawal initiated. Fires multiple times as the withdrawal advances — see [Transaction lifecycle](#transaction-lifecycle-transfers-and-withdrawals).
**`withdrawal.completed`** Payload: `transactionId`, [`details`](#transaction-lifecycle-transfers-and-withdrawals)
Withdrawal successfully completed.
**`withdrawal.failed`** Payload: `transactionId`, [`details`](#failure-reasons)
Withdrawal failed. See [Failure reasons](#failure-reasons).
### deposit
**`deposit.attributed`** Payload: `transactionId`
Deposit attribution completed.
**`deposit.pending-attribution`** Payload: `transactionId`
New deposit pending attribution.
## Transaction lifecycle (transfers and withdrawals)
For `transfer` and `withdrawal`, the three events, `initiated`, `completed`, and `failed`, track an operation across its whole lifecycle. Unlike other topics, `initiated` fires more than once: each time the operation reaches a new phase, a fresh `initiated` event arrives with a different `details` value. Read `details` to know where the operation is. `completed` fires once on success, and `failed` fires once on a terminal failure, each with its own `details` value.
Expanded lifecycle `details` are rolling out per organization. If you don't yet see a `details` field on your `transfer` and `withdrawal` events, notify your integration point of contact.
Each `initiated` event carries one of these `details` values:
| `details` | Fires when | Still cancelable? |
| :---------------------------------- | :----------------------------------------------------------------- | :---------------- |
| `queued` | Operation created, waiting on quorum approval and/or risk review | Yes |
| `quorum-met` (withdrawals only) | Quorum approvals gathered, handed to Anchorage Digital risk review | Yes |
| `signing` | Risk review passed, transaction signing begins | Yes |
| `broadcasting` (committed on-chain) | Transaction broadcast to the network | No |
The `completed` event carries a single `details` value, `completed`, once the operation settles successfully.
### Failure reasons
A `failed` event fires once if the operation ends unsuccessfully, carrying one of these `details` values:
| `details` | Meaning |
| :--------- | :------------------------------------------------------------------ |
| `rejected` | An approver or Anchorage Digital risk review rejected the operation |
| `expired` | The operation timed out before completion |
| `canceled` | The operation was canceled |
Some `failed` events arrive with no `details` field. Treat a missing `details` as an unspecified failure.
Because `initiated` now fires multiple times, order matters. Webhook delivery is at-least-once and events may arrive out of order, so use `details` rather than arrival order to track progress. See [Delivery and reliability](/knowledge-base/porto/developers/webhooks/webhooks-delivery) for handling duplicates and out-of-order events.
# Webhook testing
Source: https://docs.anchorage.com/knowledge-base/porto/developers/webhooks/webhooks-sandbox
Step-by-step guide to testing webhooks in a non-production (staging/testnet) environment with the Anchorage Digital API.
You're viewing **Porto** developer documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/developers/setting-up)
Either create your own endpoint or use the [Svix playground](https://www.svix.com/play/) for rapid testing.
Once you have an endpoint, register it via API or the web dashboard:
* **API:** [Create a webhook endpoint](/knowledge-base/api-reference/v2/webhook-notifications/create-webhook-endpoint) — use the `url` field to register the endpoint.
* **Web dashboard:** [Create webhooks](https://clientdashboard.anchorage-staging.com/webhooks/)
* **API:** [List webhook event types](/knowledge-base/api-reference/v2/webhook-notifications/list-webhook-event-types)
* **API:** [Create webhook subscriptions](/knowledge-base/api-reference/v2/webhook-notifications/create-webhook-subscriptions) — use the `endpointId` to subscribe to any or all event types.
* **Web dashboard:** [Select events](https://clientdashboard.anchorage-staging.com/webhooks/)
The validation key is used to verify that webhook messages originate from Anchorage Digital. Find it on the web dashboard or via API.
**Validation key:**
```text theme={null}
c14b7f3da18abb17b7304f925a68b18c1ea0dad6663b6b54cb67a737ecb77cd0
```
* **API:** [Get webhook validation key](/knowledge-base/api-reference/v2/webhook-notifications/get-webhook-validation-key)
To test, send testnet assets to a wallet, or attempt a withdrawal or transfer via API or the iOS app.
For a deposit event:
1. Generate a new wallet address for BTC Signet (`BTC_S`) via Postman or the API reference.
2. Use the [BTC Signet Faucet](https://signetfaucet.com/) to send testnet BTC to that address.
Once the event fires, your endpoint will receive a message like the following:
```json Deposit theme={null}
{
"payload": "eyJ0cmFuc2FjdGlvbklkIjoiNjE4Y2JkNTVlNzE2ZmFlMGVkODNjYTcyOWM4MDI2NmEifQ==",
"timestamp": 1729112450,
"message_id": "aa2dbc06-1665-44c0-bb8e-d2b0ad15a564",
"event_type": "deposit.pending-attribution"
}
```
Verify the webhook message is from Anchorage Digital using the validation key and the API signature header.
You can validate manually or use an open-source tool:
[Ed25519 signature tool](https://cyphr.me/ed25519_tool/ed.html)
The `Api-Signature` header is hex-encoded. Decode it to raw bytes before verifying.
| Field | Value |
| :----------------- | :------------------------------------- |
| Message encoding | Text (UTF-8) |
| Message | Paste the raw request body |
| Key encoding | Hex |
| Seed (private key) | Leave blank |
| Public key | Validation key |
| Signature encoding | Hex |
| Signature | Paste the `Api-Signature` header value |
The `payload` field in the response body is Base64-encoded. Decode it to retrieve the event data.
Use a [Base64 decode tool](https://www.base64decode.org/) — paste the `payload` value into the decode input.
Use the decoded `transactionId` to fetch full details from the API:
* [List transactions](/knowledge-base/api-reference/v2/transactions/list-transactions)
# Vaults quick-start
Source: https://docs.anchorage.com/knowledge-base/porto/getting-started/accounts-vaults
Quick guide to creating and managing vaults in Porto.
You're viewing **Porto** documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/users/overview)
## Create a vault
Administrators can create vaults to organize and manage digital assets. Each vault has its own users, permissions, and approval policies.
Scroll down in the app and tap **Create new vault**.
Provide a name, description, and select the account.
Add at least 3 members and configure who can initiate and approve operations.
Review the details and submit for biometric approval. Quorum administrators will approve the operation.
For detailed instructions on vault creation, policies, and management, see [Vaults & wallets](/knowledge-base/porto/vaults-wallets/vaults).
## Manage vault access
You can add or remove users from a vault, and configure their permissions through the vault settings.
**Next step:** See [Vaults & wallets](/knowledge-base/porto/vaults-wallets/vaults) for detailed instructions on managing vaults, creating policies, and configuring users.
# Managing devices
Source: https://docs.anchorage.com/knowledge-base/porto/getting-started/device-management
Control which devices can access your Porto account and configure security settings.
You're viewing **Porto** documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/users/overview)
Devices are the phones, tablets, or computers from which you access Porto. You can view all devices connected to your account, set up biometric authentication, and remove devices you no longer use.
## View your devices
From the home screen, tap the **Settings** icon.
Look for a **Security** or **Devices** section in settings.
You'll see a list of all devices that have access to your Porto account, including the device name, last access time, and whether biometric authentication is enabled on that device.
## Set up biometric authentication
Biometric authentication (Face ID or Touch ID) secures your account by requiring your fingerprint or face recognition to approve sensitive operations like withdrawals and approvals. This is required for most Porto transactions.
From the home screen, tap the **Settings** icon.
Look for a section labeled **Biometric authentication**, **Security**, or **Face ID and Touch ID**.
Tap **Enable** or **Set up Face ID/Touch ID** for your current device.
Your device's operating system (iOS) will guide you through enrolling your face or fingerprint. Complete this process to activate biometric authentication.
Once enrolled, your biometric data will be used to authorize transactions and account access on this device.
Biometric data is stored securely on your device and is never sent to Porto's servers. Only your device can approve biometric requests.
## Remove a device
If you sell your phone, stop using a device, or believe a device has been compromised, you can remove it from your Porto account.
From the home screen, tap the **Settings** icon.
Go to the **Security** or **Devices** section.
Tap on the device you want to remove from your account.
Select **Remove device** or **Disconnect** to revoke this device's access.
Depending on your account's security policies, you may need to complete biometric authentication to confirm the removal.
Removing a device immediately revokes its access to your Porto account. If you accidentally remove the device you're using, you'll need to log in again to regain access.
## Device security best practices
* **Use biometric authentication** on all your devices — it's the fastest and most secure way to approve transactions
* **Remove unused devices** — if you no longer use a phone or tablet, remove it from your account to reduce your attack surface
* **Don't share devices** — your Porto account should not be accessed from shared or public devices
* **Keep your device updated** — always install the latest iOS updates and security patches
* **Lock your device** — set a strong passcode or use Face ID/Touch ID on your device itself, in addition to Porto's security measures
* **Use trusted Wi-Fi or mobile networks** — avoid accessing Porto on public Wi-Fi networks without a VPN
## If you lose a device
If your phone or tablet is lost or stolen:
1. **Remove the device immediately** — Go to settings on another device and remove the lost device from your account
2. **Change your password** — Log in to your account and update your password to prevent unauthorized access
3. **Contact your organization's administrator** — Let them know your device was lost; they may want to review recent activity or adjust security policies for your account
4. **Check activity history** — Review the [Activity log](/knowledge-base/porto/assets/activity-history) to see if any unauthorized transactions occurred
# How it works
Source: https://docs.anchorage.com/knowledge-base/porto/getting-started/how-it-works
Understand Porto's key concepts and how institutional self-custody works.
You're viewing **Porto** documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/users/overview)
Porto is an institutional self-custody wallet that gives your organization full control over digital assets while maintaining institutional-grade security. Here's how the core concepts work together.
Secure containers that hold your digital assets. Each vault has its own set of users, policies, and approval requirements.
Within each vault, you can create multiple wallets for different assets. Each wallet has a unique deposit address.
Organization members with specific permissions. Roles determine who can initiate operations, approve transactions, and manage settings.
Rules that define how operations work. Policies set approval requirements, quorum members, and permissions for different actions.
Groups of approvers required to authorize operations. Quorums ensure no single person can move assets without oversight.
The process of authorizing sensitive operations. Approvals involve biometric authentication and quorum sign-offs based on your policies.
## The approval flow
Operations like transfers, user management, and policy changes follow a standard approval flow:
1. **Initiator submits** — An authorized user starts the operation and provides details
2. **Initiator approves** — They complete biometric authentication on their device
3. **Quorum approves** — Policy-designated approvers review and authorize the operation
4. **Anchorage Digital reviews** — For certain operations, our compliance team provides final review
5. **Operation executes** — Once all approvals are complete, the operation is processed
## Self-custody with institutional security
Porto gives you true self-custody — you control your private keys and digital assets — while maintaining the security and governance controls institutions require:
* **Full control**: You hold the keys. Anchorage Digital never has access to your assets.
* **Multi-signature**: Operations require approval from designated team members.
* **Audit trail**: Every action is logged and visible in your activity history.
* **Flexible policies**: Configure approval requirements for different operation types.
* **Team collaboration**: Distribute responsibilities across your organization.
## Getting started
Ready to set up your organization? Start with these guides:
* [Logging in & homepage](/knowledge-base/porto/getting-started/login-homepage) — Your first steps
* [Mobile app & browser extension](/knowledge-base/porto/getting-started/mobile-app) — Download and install
* [Setting up participants](/knowledge-base/porto/getting-started/setup-participants) — Add your team
* [Creating vaults](/knowledge-base/porto/vaults-wallets/vaults) — Organize your assets
# Joining an account
Source: https://docs.anchorage.com/knowledge-base/porto/getting-started/joining-accounts
Accept invitations and join existing Porto organizations.
You're viewing **Porto** documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/users/overview)
When a team member invites you to their Porto organization, you'll receive an email with instructions. Follow these steps to accept the invitation and join their account.
## Accept an invitation
Look for an email from Porto with the subject line "You're invited to join \[Organization Name]."
Click the link in the email to start the acceptance process. This opens the Porto app or redirects you to download it if you don't have it installed.
If you're a new user, create a Porto account with your email and password. If you already have a Porto account, sign in with your credentials.
You'll see the organization name and the role you're being added with (Viewer, Operator, Initiator, Approver, or Admin). Review these details carefully.
Tap **Accept** or **Join organization** to confirm you want to join this account. You may be asked to complete biometric authentication to secure your access.
If your organization requires additional security measures, you may need to set up biometric authentication, device enrollment, or other security features before full access is granted.
Invitations typically expire after 30 days. If your invitation has expired, ask the organization's administrator to send a new one.
## After accepting
Once you've accepted an invitation, you'll have access to the organization's vaults and assets based on your assigned role. You can now:
* View vaults and assets you have permission to access
* Initiate operations (deposits, withdrawals) based on your role
* Approve operations if you're designated as an Approver or Admin
* Access the Activity log to see transaction history
For details on what each role can do, see [Permission levels](/knowledge-base/porto/users/permission-levels).
## Multiple accounts
After accepting invitations, you may be part of multiple Porto organizations. You can [switch between accounts](/knowledge-base/porto/getting-started/switching-accounts) from the home screen.
## Troubleshooting
**I didn't receive an invitation email:**
* Check your spam or junk folder — sometimes invitation emails get filtered
* Ask your organization's administrator to resend the invitation
**The link in my email isn't working:**
* Try opening the Porto app directly and looking for an "Pending invitations" section
* If that doesn't work, contact your organization's administrator for a new invitation
**I accepted but don't see any vaults:**
* The administrator may not have granted you access to specific vaults yet
* Ask your administrator to add you to the vaults you need access to, or check your assigned role — some roles have more limited visibility
**I want to decline the invitation:**
* Ignore the email or delete it if you don't want to join this organization
* If you've already accepted and want to leave, ask your organization's administrator to remove you
# Logging in & homepage
Source: https://docs.anchorage.com/knowledge-base/porto/getting-started/login-homepage
Access Porto and navigate the home screen.
You're viewing **Porto** documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/users/overview)
Once you've downloaded the Porto app, log in to access your organization's vaults and assets.
## Log in to Porto
Launch the Porto app on your device. You'll see the login screen.
Type the email address associated with your Porto account.
Use Face ID or Touch ID to verify your identity. This protects your account from unauthorized access.
You'll be taken to the home screen showing your organization's vaults and assets.
## Home screen overview
The home screen is your central hub for managing vaults, viewing assets, and tracking activity.
### Top navigation
* **Vaults icon** — View all vaults and their assets
* **Activity icon** — See recent transactions and operations
* **Settings icon** — Manage account, team, and organization settings
### Vault overview
Each vault displays:
* **Vault name** — Identifies the vault
* **Total balance** — Combined value of all assets in the vault (if pricing is enabled)
* **Asset list** — Each asset in the vault with current balance and wallet count
* **Users count** — Number of team members with access to the vault
### Quick actions
From the home screen, you can:
* **View asset details** — Tap an asset to see wallet addresses and recent transactions
* **Send assets** — Initiate a transfer to a trusted destination
* **Receive assets** — Share your wallet addresses for deposits
* **Access settings** — Manage vault policies, team members, and permissions
## Switching accounts
If your organization uses multiple accounts, you can switch between them from the home screen.
Tap the account name or switcher icon at the top of the home screen.
Choose the account you want to access from the list.
Depending on your device settings, you may need to use biometric authentication.
You can only manage one account at a time. To switch back, use the account switcher again.
## Logging out
From the home screen, tap the **Settings** icon.
Scroll to the bottom and tap **Log out**.
Confirm that you want to log out. You'll be returned to the login screen.
Logging out is optional—the app remains secure with biometric authentication. If you're using a shared device, logging out adds extra protection.
# Mobile app & browser extension
Source: https://docs.anchorage.com/knowledge-base/porto/getting-started/mobile-app
Download the Porto iOS app and set up the browser extension.
You're viewing **Porto** documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/users/overview)
## iOS app download
Download the Porto by Anchorage Digital app from the Apple App Store by searching for "Porto by Anchorage Digital" and tapping **Get**.
You may need to upgrade to the latest iOS software to download the app. The app is available in supported countries.
## Browser extension
The Anchorage Digital browser extension connects your Porto wallets directly to decentralized apps (dApps).
[Download the Anchorage Digital Browser Extension for Chrome](#)
### Log in to your organization
Log in using the same credentials as your web dashboard.
Open the Anchorage Digital browser extension in Chrome.
On your Porto iOS app, tap **Settings**, then tap **Web dashboard login**, and select **QR Code**.
Scan the QR code displayed in the browser extension.
Review the location shown on your device and allow access to complete login.
### Enabled networks
New chains are added to the browser extension regularly. You can view all enabled chains in the **Networks** filter within the **Wallets** tab.
### Connect a wallet to an external app
Open an external app (dApp) in your browser.
Select **Connect** in the top right corner of the dApp.
Select **Anchorage Digital** from the list of wallet options.
If you don't see Anchorage Digital listed, contact [portohelp@anchorage.com](mailto:portohelp@anchorage.com).
Filter by vault or select a recently used wallet to find the account you want to connect. Select the wallet to view its details and balance information.
Select **Connect** to finish establishing the connection.
### Switch wallets
You can switch the connected wallet after you have established a connection.
Open the Anchorage Digital browser extension.
Go to the **Wallets** tab to see your currently connected wallet.
Search for a different wallet by vault, network, or name.
Select **Connect** on the wallet card to switch the connection.
Alternatively, switch wallets from the Wallet details page by selecting **Connect to external app**.
### Disconnect a wallet
You can disconnect your wallet in three ways:
Open the browser extension, select the dApp icon in the top right, and select **Disconnect wallet**.
Select the connected wallet, select **More** (three dots) in the top right, and select **Disconnect wallet**.
Select the connected wallet in the external app interface and select **Disconnect wallet**.
### Explore external apps
To open a recently used app, go to the **Explore** tab in the browser extension. The top section displays your five most recently used apps. Select an app card to open it in a new tab.
You can also view Top Apps used on Porto from the **Explore** tab.
# Setting up participants
Source: https://docs.anchorage.com/knowledge-base/porto/getting-started/setup-participants
Add your team members to your organization for collaboration.
You're viewing **Porto** documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/users/overview)
Before you can manage vaults and assets, you need to add your team members as participants in your Porto organization. Each participant gets a role that defines their permissions.
## Add a participant
From the home screen, tap the **Settings** icon.
Tap **Team** or **Participants**.
Tap **Add participant** or the **+** button.
Type the email address of the team member you want to invite.
Select their [permission level](/knowledge-base/porto/users/permission-levels):
* **Viewer** — Read-only access to vaults
* **Operator** — Can initiate deposits and receive requests
* **Initiator** — Can initiate transfers and withdrawals
* **Approver** — Can approve operations from others
* **Admin** — Full access to settings, users, and operations
Select which vaults this participant should have access to. You can adjust this later.
Verify the email and role, then tap **Send invite**.
If you have admin permissions, you may need to approve adding this participant. Complete biometric authentication to confirm.
The invited participant will receive an email with instructions to download the Porto app and join your organization. They'll need to accept the invitation within the app.
## Participant roles
| Role | Permissions |
| :------------ | :------------------------------------------------------- |
| **Viewer** | View vault assets and activity (no action permissions) |
| **Operator** | View assets, create receive addresses, request deposits |
| **Initiator** | Operator + initiate transfers and withdrawals |
| **Approver** | Review and approve operations from others |
| **Admin** | Full access—manage users, vaults, policies, and settings |
See [Permission levels](/knowledge-base/porto/users/permission-levels) for detailed permission matrices.
## Participant status
Participants in your organization show different statuses:
* **Active** — Participant has joined and can access vaults
* **Pending** — Invitation sent, awaiting participant acceptance
* **Inactive** — Participant has been removed from the organization
## Manage participant access
After adding a participant, you can:
* **Change their role** — Update permissions at any time
* **Add to more vaults** — Grant access to additional vaults
* **Remove from vaults** — Restrict access to specific vaults
* **Remove from organization** — Complete removal (see [Remove user](/knowledge-base/porto/users/remove-user))
## Best practices
* **Principle of least privilege** — Give each participant only the minimum permissions they need
* **Separate roles** — Use different people for initiating and approving to prevent unauthorized operations
* **Regular audits** — Review participant access quarterly to ensure it's still appropriate
* **Document approvers** — Keep a record of who your policy designates as approvers for compliance
## Next steps
For detailed instructions on managing user permissions, removing users, and adjusting vault access, see the [Users & access control](/knowledge-base/porto/users/managing-users) section.
# Switching accounts
Source: https://docs.anchorage.com/knowledge-base/porto/getting-started/switching-accounts
Switch between multiple Porto organizations.
You're viewing **Porto** documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/users/overview)
If you're part of multiple Porto organizations, you can easily switch between them without logging out. Each organization is a separate account with its own vaults, users, and policies.
## Switch accounts
From anywhere in the Porto app, tap the home icon or navigate to the main screen.
Look for the account name or organization name at the top of the screen (usually in the header or navigation bar). Tap it to open the account switcher menu.
Choose the organization you want to switch to from the list of accounts you're a member of.
The app will load the new account's vaults, settings, and activity. You're now viewing that organization's data.
Switching accounts doesn't log you out of your Porto user account — it just changes which organization's data you're viewing. Your login credentials remain the same.
## Account-specific information
Each account shows:
* **Vaults** — The vaults that belong to this organization
* **Activity** — Transactions, approvals, and user management changes for this organization only
* **Settings** — Organization-specific settings, policies, and user management (if you have admin access)
* **Users** — The participants in this organization and their roles
You cannot see other organizations' data while viewing a different account. Your permissions and role are organization-specific — you might be an Admin in one organization and a Viewer in another.
## Managing accounts
To add yourself to a new organization, you need an invitation from that organization's administrator. See [Joining an account](/knowledge-base/porto/getting-started/joining-accounts) for details.
To remove yourself from an organization or have an administrator remove you, see [Removing a user](/knowledge-base/porto/users/remove-user).
## Biometric authentication
When you switch accounts, the app may ask you to complete biometric authentication (Face ID or Touch ID) to confirm the switch, depending on your organization's security policies. This helps ensure that only authorized users can access sensitive vaults and assets.
# What is Porto?
Source: https://docs.anchorage.com/knowledge-base/porto/overview
Porto by Anchorage Digital is our institutional self-custody solution allowing for unmatched access to DeFi & Web3.
Porto by Anchorage Digital is an institutional self-custody wallet built with the security and technology Anchorage Digital is best known for, enabling unmatched access to DeFi & Web3 and seamless integration with the Anchorage Digital platform.
You're viewing **Porto** documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/users/overview)
This documentation is for Porto users only. Any external sharing beyond authorized Porto users requires approval from Anchorage Digital. For support, contact [portohelp@anchorage.com](mailto:portohelp@anchorage.com).
## About Porto by Anchorage Digital
Porto makes institutional self-custody simple, while ensuring assets are safeguarded using a robust security architecture.
World-class security with end-to-end cryptographic integrity, FIPS-140 policy and private key security, and hardware security modules (HSMs).
Transact and self-custody ERC and SPL tokens—with support for more Layer 1s coming soon.
Connect to dApps for staking, reward-claiming, governance voting, and more.
## Device requirements
All users are required to have an iOS device running iOS 18 or later with Touch ID or Face ID enabled. The Porto security model leverages the secure enclave only found in the Apple device. During on-boarding, each device is tethered to our HSMs.
**Supported devices:**
* iPhone 8 or later with Face ID or Touch ID enabled
* iPad 5th generation or later
## On-boarding
Prior to on-boarding, all users should download the Porto by Anchorage Digital app by searching "Porto by Anchorage Digital" in the Apple App Store.
You may need to upgrade to the latest iOS software to download the app.
Porto recommends on-boarding with at least 3 users. There are two critical steps to secure your organization and complete on-boarding:
The organization recovery document is used to restore your access to Porto if all admin users lose access to all Porto-enrolled devices. Store it in a safe and redundant manner so that Anchorage Digital can help you use it to restore access to Porto.
Unlike a seed phrase, this PDF is not sensitive material on its own—it is only relevant within Anchorage Digital's security architecture.
Anchorage Digital cannot restore your access if you lose your organization recovery document. As a best practice, we recommend sharing the document with the other admins on the account. Do not lose it!
It can always be re-downloaded in the settings tab, under the header Recover access.
We do not retain a copy of the document and we will never ask you to send us a copy of the document.
Porto cannot restore your access if you lose your organization recovery document.
Wallet recovery shares can be used decrypt and expose the private key of your one or more of your wallets. With the private key of a wallet you can access your funds outside of Porto. A single wallet recovery share is not sensitive on its own, but with 2 out of 3 shares, your wallets become accessible outside of Porto.
During or after onboarding, you can distribute each share to a different team member to ensure they are kept separate and secure. Maintaining the separation and security of each wallet recovery share is crucial for safeguarding your wallets against unauthorized access.
## Security model
Every product decision is informed by deep expertise in security. The result is a wallet that sets the standard for digital asset security.
Porto forgoes the use of usernames and passwords, which are susceptible to fraud, impersonation, and abuse.
Porto does not use emails or phone numbers, so attackers cannot gain access by triggering email or SMS-based account recovery.
Only pre-approved devices may access an account.
Users can only unlock the app using Face ID or Touch ID. Sensitive operations always require biometric approval.
### Authentication via hardware security modules
Once a transaction is fully approved by the organization's team, it advances to our specialized hardware system to be processed within minutes.
* **Hardware security modules**: Private keys are generated on air-gapped HSMs. The system signs transactions without ever exposing private keys.
* **Hardware-enforced logic**: Custom logic verifies that each operation has a valid quorum of approvals. Transactions can process only if the quorum threshold is met.
* **High-security data centers**: Porto HSMs are housed in secure data centers around the world.
## How it works
The Porto transaction flow is designed to prove with certainty that a given transaction reflects an organization's intent. Once all three steps are complete, Porto processes the transaction within minutes.
Sensitive operations require the user's biometric approval using Face ID or Touch ID. Each user's identity is tied to a unique and unforgeable cryptographic key, created and stored in the iOS device's Secure Enclave, so only authorized devices can access the account.
Every transaction requires approval from a predefined number of users on the organization.
HSMs process the transaction once quorum approval is met. The system signs transactions without ever exposing private keys.
## Access and policies
### User permission levels
The platform has three permission levels. Users can hold multiple roles, and each vault can have its own user access configuration.
| Permission | Edit vault & org policies | Add/remove users | Create vault | Add/remove trusted destinations | Deposit & withdraw | View balances |
| ------------- | ------------------------- | ---------------- | ------------- | ------------------------------- | ------------------ | ------------- |
| **Admin** | Supported | Supported | Supported | Supported | Supported | Supported |
| **Operator** | Not supported | Not supported | Not supported | Not supported | Supported | Supported |
| **View-only** | Not supported | Not supported | Not supported | Not supported | Not supported | Supported |
* **Admin**: Full access to perform administrative tasks, including the ability to create and modify policies, add and delete users, manage trusted destinations, and create and edit vaults.
* **Operator**: Access to perform operations in a vault, including initiating and approving withdrawals.
* **View-only**: View permissions to vaults and the ability to view balances.
### Device-based account access
| Action | iOS | Web dashboard | Quorum needed |
| ----------- | --------- | ------------- | ------------- |
| Deposits | Supported | Supported | Not required |
| Withdrawals | Supported | Supported | Required |
## Vault overview
Users can take advantage of multi-asset vaults to organize assets in the Porto wallet. There is no limit on the number of vaults.
Each vault must have a minimum of 3 members and a minimum quorum of 2 approvers. With those conditions met, quorum approval can be customized. The number of members and approvers may be influenced by factors like the use case for each vault—frequent or infrequent withdrawals—and the amount of value in the vault.
### Customize and configure policies
* **Customize all permissions**: Configure permission policies across the entire organization and specific to each vault, ensuring everyone has only the permissions needed.
* **Configure quorums and sub-quorums per vault**: Set one vault's quorum to require approvals from 2 of 9 members, and another's to require approvals from 5 of 6 members. Designating a sub-quorum of required approvers is also an option.
* **Empower administrators**: Unlike other users, administrators can—if approved by the necessary quorum—add and delete users, add and remove trusted destinations, create and edit vaults, and change organizational policies.
**Quorum definitions:**
* **Quorums**: A group of users with permission to initiate and approve operations, such as default, governance, staking, or withdrawal operations.
* **Sub-quorums**: Additional approval layers ensuring operations cannot proceed without a set number of approvals from designated members. Policies may have as many sub-quorums as needed.
For more details, see [Creating a vault](/knowledge-base/porto/getting-started/accounts-vaults) and [Adding users](/knowledge-base/porto/getting-started/adding-users).
# Adding rules to policies
Source: https://docs.anchorage.com/knowledge-base/porto/policies/adding-rules
Create custom approval rules for vaults and admin policies.
You're viewing **Porto** documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/users/overview)
Rules define specific approval requirements for operations in your vault or organization. By adding rules, you can create fine-grained control over who must approve which operations and under what conditions.
## What is a rule
A rule is a set of conditions that triggers specific approval requirements:
* **When:** Conditions that must be met (operation type, amount, address type, etc.)
* **Then:** Approval requirements (who must approve, how many, etc.)
**Example rule:**
* "When: A withdrawal over \$100,000"
* "Then: 2 of 3 senior officers must approve"
## Types of rules you can create
| Rule type | Condition | Use case |
| :------------------ | :------------------------------------------- | :------------------------------------------- |
| **Operation-based** | Withdrawal, deposit, transfer, policy change | Different approvals for different operations |
| **Amount-based** | Greater than $X, less than $Y | Higher approval for large transactions |
| **Address-based** | To trusted destination, to new address | Stricter approval for new recipients |
| **Time-based** | During business hours, on weekdays | Different approval rules by time |
| **Role-based** | By initiator's role | Different rules for different user types |
| **Combination** | Multiple conditions together | Complex, nuanced approval logic |
## Adding a rule
Go to **Settings** > **Policies** > **Vault policy** or **Admin policy**.
Select **Add rule**, **Create rule**, or **New rule**.
Specify when this rule applies. Check all that apply:
* **Operation type:** What operation triggers this rule?
* **Amount:** Any amount, or only amounts above/below certain thresholds?
* **Recipient:** Any address, only trusted destinations, only new addresses?
* **Time:** Any time, business hours only, weekdays only?
* **Initiator role:** Any role, specific roles only?
If you don't specify a condition, the rule applies regardless of that factor.
* Leave amount blank = applies to any amount
* Leave recipient blank = applies to any address
Specify who must approve:
* **Number of approvers:** 1, 2, 3, all, etc.
* **Approver selection:** Any approver, specific role, specific person
* **Voting rule:** Simple majority, unanimous, weighted, etc.
How long before the approval request expires:
* **Short (4-12 hours):** For time-sensitive operations
* **Standard (24 hours):** Most common
* **Long (48-72 hours):** For less urgent approvals
Tap **Save** or **Create rule**.
Tap **Submit policy** or **Apply changes**. The new rule becomes active.
If your vault or admin policy requires approval for policy changes, the rule change must be approved.
## Rule examples
### Example 1: Amount-based rule
**Condition:** Withdrawal amount
* Up to \$10,000: 1 approver needed
* $10,001 - $100,000: 2 approvers needed
* Over \$100,000: 3 approvers needed
**Configuration:**
* Create 3 rules with overlapping amount ranges
* Each rule specifies the approval threshold
### Example 2: Address-based rule
**Condition:** Recipient address type
* To [trusted destination](/knowledge-base/porto/assets/trusted-destinations): 1 approver
* To new address: 2 approvers
**Configuration:**
* Rule 1: If recipient in trusted destinations, 1 approver
* Rule 2: If recipient not in trusted destinations, 2 approvers
### Example 3: Combined rule
**Condition:** Withdrawal > \$50,000 to new address
* **Then:** 2 of 3 CFO, COO, CEO must approve
**Configuration:**
* Amount > \$50,000
* Recipient = new address (not pre-approved)
* Approvers = 2 of \{CFO, COO, CEO}
### Example 4: Time-based rule
**Condition:** Large withdrawal during non-business hours
* **Then:** Requires 3 approvers (extra scrutiny outside business hours)
**Configuration:**
* Amount > \$X
* Time = outside 9 AM - 5 PM weekdays
* Approvers = 3 required
## Rule priority and conflicts
If multiple rules could apply to the same operation, the **most specific rule wins**:
**Rule priority (most to least specific):**
1. All conditions specified (operation + amount + address + time)
2. 3 conditions specified
3. 2 conditions specified
4. 1 condition specified
5. No conditions specified (default rule)
**Example:**
* Rule A: "Withdrawals over \$100k" = 2 approvers
* Rule B: "Withdrawals to new addresses" = 2 approvers
* Rule C: "Withdrawals over \$100k to new addresses" = 3 approvers (this rule wins)
For a \$150k withdrawal to a new address, Rule C (most specific) applies.
## Default rules
Every policy should have a **default rule** with no conditions — this applies when no other rule matches:
* **Default rule:** "All withdrawals not covered by other rules" = 1 approver
* **Purpose:** Catch any operation not covered by other rules
* **Recommendation:** Set default to your standard approval requirement
## Draft rules and testing
Before making a rule active, you can:
1. **Create as draft** — Save it without activating
2. **Test it** — See how it would apply to recent operations
3. **Refine** — Adjust thresholds or requirements
4. **Activate** — Make it official
Some systems don't support draft mode — you may need to activate immediately.
## Common mistakes to avoid
**Mistake 1: Overlapping rules with different requirements**
* Solution: Be specific with conditions; avoid creating conflicting rules
**Mistake 2: No default rule**
* Solution: Always create a default rule to catch operations not covered by specific rules
**Mistake 3: Rules that never match**
* Example: Rule for "withdrawals over \$1 million" in a vault that never handles amounts that large
* Solution: Review rules quarterly and remove ones that never apply
**Mistake 4: Too many approvers required**
* Solution: Creates bottlenecks; use tiered approvals based on risk
**Mistake 5: Time-based rules that are too narrow**
* Example: Rule that applies only 10 AM - 11 AM weekdays
* Solution: Use broader time windows or avoid time-based rules unless necessary
## Rule documentation
When creating rules, document:
* **Why:** Why is this rule necessary? What risk does it address?
* **When:** Under what conditions does it apply?
* **Approval:** Who must approve, and why?
* **Changes:** When was it created/modified?
* **Owner:** Who is responsible for this rule?
This documentation helps future administrators understand and maintain rules.
## Managing rules over time
Rules should be reviewed quarterly:
1. **Check effectiveness** — Are the rules achieving their purpose?
2. **Spot trends** — Do new operation patterns suggest new rules are needed?
3. **Remove unused rules** — If a rule never applies, delete it
4. **Adjust thresholds** — If business volume changes, update amount thresholds
5. **Communicate changes** — Let users know about new/modified rules
See [Editing rules](/knowledge-base/porto/policies/editing-rules) and [Deleting rules](/knowledge-base/porto/policies/deleting-rules) for modification instructions.
# Adding subquorums
Source: https://docs.anchorage.com/knowledge-base/porto/policies/adding-subquorums
Create nested approval structures with subquorums for complex approval flows.
You're viewing **Porto** documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/users/overview)
Subquorums allow you to create nested approval requirements — for example, "2 of 3 people from Department A, OR 1 person from Department B." This enables complex, flexible approval structures for sophisticated organizations.
Subquorums are an advanced feature. Standard quorum requirements may be sufficient for most organizations. Ask your administrator if subquorums are enabled for your organization.
## What is a subquorum
A subquorum is a group of approvers with its own quorum requirement. Multiple subquorums can be combined into a single policy using logical operators (AND, OR).
**Example:**
* Subquorum A: 2 of 3 CFO, Controller, Treasurer
* Subquorum B: VP of Risk
* Policy: (Subquorum A) AND (Subquorum B)
* Result: Both the finance group AND the risk officer must approve
## When to use subquorums
Use subquorums when:
* **Distributed approval** — Different departments must approve different aspects
* **Escalation tiers** — Different approval groups for different severity levels
* **Specialist sign-off** — Legal, compliance, or other specialists must approve certain operations
* **Backup approvers** — Alternative approval paths if primary approvers unavailable
* **Multi-entity** — Multiple legal entities in one vault each need to approve
**Example scenarios:**
| Scenario | Subquorum structure |
| :---------------------------------------- | :-------------------------------------------- |
| Treasury + Risk approval | (2 of 3 treasury) AND (1 of 2 risk) |
| Any investor can approve, or fund manager | (1 of 10 investors) OR (fund manager) |
| Escalated withdrawals | (1 of 3 operations) AND (1 CFO) |
| Multi-geography | (1 of 2 US officers) AND (1 of 2 EU officers) |
## Add a subquorum
Go to **Settings** > **Policies** > **Vault policy**.
Look for **Add subquorum**, **Create approval group**, or **Nested quorum**.
Tap **Add subquorum** or **Create group**.
Give it a descriptive name (e.g., "Treasury Committee," "Risk Officers," "Legal Signatories").
Select which users are members of this subquorum.
How many of these members must approve?
* 1 of X: Any one member
* 2 of X: Any two members
* All of X: All members required
Tap **Save** or **Create group**.
Repeat to create additional subquorum groups.
Specify how subquorums relate to each other:
* **AND:** Both subquorums must approve
* **OR:** Either subquorum can approve
* **Advanced:** Weighted or complex combinations
Tap **Save policy** or **Apply changes**. The new subquorum structure takes effect.
If policy changes require approval, the new subquorum must be approved.
## Subquorum examples
### Example 1: Finance + Risk
**Subquorum A (Finance):** 2 of \{CFO, Controller, Treasurer} **Subquorum B (Risk):** 1 of \{VP Risk, Compliance Officer} **Requirement:** Finance AND Risk (both must approve)
**Result:** For a large withdrawal, the CFO and Controller must both approve, AND the VP Risk must also approve.
### Example 2: Any specialized approver OR escalated
**Subquorum A (Regular):** 1 of \{Treasurer, Assistant Treasurer} **Subquorum B (Backup):** CFO **Requirement:** Subquorum A OR Subquorum B
**Result:** For routine operations, one Treasurer is enough. If both are unavailable, the CFO can approve as backup.
### Example 3: Multi-geography
**Subquorum A (US):** 1 of \{CEO US, CFO US} **Subquorum B (EU):** 1 of \{CEO EU, CFO EU} **Requirement:** US AND EU (both regions must approve)
**Result:** Major operations require one approver from US and one from EU.
### Example 4: Escalating approval
**Small transactions (\<\$100k):**
* Subquorum A: 1 of 3 operations staff
**Large transactions (>\$100k):**
* Subquorum A: 1 of 3 operations staff
* Subquorum B: CFO
* Requirement: A AND B (both required for large)
**Result:** Small transactions are fast; large ones require operations + CFO.
## Subquorum member management
### Adding members to a subquorum
Go to **Settings** > **Policies** > **Vault policy**.
Locate the subquorum you want to modify.
Select **Edit subquorum** or the **pencil** icon.
Tap **Add member** and select a user.
Tap **Save** or **Update**.
### Removing members from a subquorum
Locate the subquorum in your vault policies.
Select **Edit**.
Find the member you want to remove and tap **Remove** or the **X** button.
Tap **Save** or **Update**.
**Important:** If you reduce members below the quorum requirement (e.g., remove someone from a "2 of 3" subquorum, leaving 2 members), the quorum becomes "2 of 2" (all required).
## Subquorum naming best practices
Use clear, descriptive names:
| Good name | Avoid |
| :------------------- | :--------- |
| "Treasury Committee" | "Group 1" |
| "Risk Officers" | "SQ1" |
| "US Signatories" | "A" |
| "Backup Approvers" | "Quorum 2" |
Clear names help users understand approval flows.
## Complex subquorum structures
For advanced setups, you can combine subquorums with rules:
**Example: Tiered approval with subquorums**
* **Small withdrawals (\<\$50k):** Subquorum A (1 of 2 treasurers)
* **Medium (**$50k - $**500k):** Subquorum A AND Subquorum B (treasurers + CFO)
* **Large (>\$500k):** Subquorum A AND Subquorum B AND Subquorum C (treasurers + CFO + CEO)
This creates an escalating approval structure where larger operations require more oversight.
## Approval of subquorum changes
Adding new subquorums requires approval:
* **Submitter:** The person creating the subquorum
* **Approvers:** Based on your admin policy
* **Audit trail:** Creation is recorded with all details
* **Effective date:** Takes effect immediately after approval
## Common mistakes with subquorums
**Mistake 1: Impossible requirements**
* "2 of 2" when you need fallback (too strict)
* Solution: Use "1 of 2" with escalation rule
**Mistake 2: Redundant subquorums**
* Creating two nearly identical subquorums
* Solution: Use one subquorum and adjust the requirement
**Mistake 3: Too complex**
* 5+ nested subquorums with multiple AND/OR combinations
* Solution: Simplify; most organizations need at most 3-4 subquorums
**Mistake 4: Stale members**
* Subquorum includes people who've left the organization
* Solution: Regularly review and update subquorum membership
## Documenting subquorum structures
Document your subquorum design:
```text theme={null}
Vault: Treasury
Subquorum A (Finance Committee):
- Members: CFO, Controller, Treasurer
- Requirement: 2 of 3
- Purpose: Daily operations approval
Subquorum B (Risk):
- Members: VP Risk, Compliance Officer
- Requirement: 1 of 2
- Purpose: Risk assessment and approval
Policy requirement: Finance Committee AND Risk approves
Examples:
- Withdrawal $50k: CFO + Controller (Finance) + Compliance Officer (Risk) approve
- Withdrawal $200k: Same as above
- All withdrawals require both subquorum approvals
```
## Testing subquorum structure
Before finalizing, test your structure:
1. **Trace through scenarios** — Mentally trace an operation through your subquorum approval
2. **Check for gaps** — Can every operation find a valid approval path?
3. **Verify fallback paths** — If one approver is unavailable, can others still approve?
4. **Confirm no deadlocks** — Is any approval path impossible?
See [Managing rules](/knowledge-base/porto/policies/managing-rules) for ongoing subquorum management and [Editing subquorums](/knowledge-base/porto/policies/editing-subquorums) for modification instructions.
# Admin policies
Source: https://docs.anchorage.com/knowledge-base/porto/policies/admin-policies
Configure administrator policies and quorum settings.
You're viewing **Porto** documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/users/overview)
All organization-level operations follow the default administrator policy unless administrators customize settings per operation type: User management, Trusted destination, Vault, and API management operations.
Any changes to administrator policies are subject to quorum approval according to the policy in place. You will be prompted to submit biometric approval on your iOS device.
## Viewing and editing administrator policies
To access administrator policies, tap the **Settings** icon, then tap **Admin policy** and select the policy to edit.
## Base quorum members
The base quorum defines the pool of administrators eligible to approve operations under the administrator policy.
### Editing base quorum members
Tap **Rules**, then tap the three-dot menu next to the rule you want to edit and select **Edit rule**.
In **Edit rule**, tap the **Quorum is** field, select the members who can approve operations under this rule, and tap **Continue**.
Tap **Done** to save the rule. Follow the prompts to submit biometric approval — quorum approval is required.
Other administrators will receive a notification to approve the action. Once quorum is met, Anchorage Digital will review the operation.
## Base quorum approvals
The approval limit defines how many base quorum members must approve an operation before it can proceed.
### Editing base quorum approvals
Tap **Rules**, then tap the three-dot menu next to the rule you want to edit and select **Edit rule**.
In **Edit rule**, use the stepper under **Number of approvals required** to set how many quorum members must approve.
Tap **Done** to save the rule. Follow the prompts to submit biometric approval — quorum approval is required.
## Sub-quorums
Sub-quorums add an additional layer of approval security. Each sub-quorum establishes a prerequisite: any operation falling under the policy cannot be completed without a preset number of approvals from the designated sub-quorum members.
Administrators can add as many sub-quorums as needed for each account-level policy.
### Adding a sub-quorum
Tap **Rules**, then tap the three-dot menu next to the rule you want to edit and select **Edit rule**.
In **Edit rule**, tap **Add sub-quorum**.
From the base quorum's approver pool, select at least one member for the sub-quorum and tap **Continue**.
Set the number of approvals this sub-quorum requires and tap **Continue**.
Give the sub-quorum a name and an optional description, then tap **Finish**.
Back in **Edit rule**, confirm the new sub-quorum, then tap **Done**. Follow the prompts to submit biometric approval — quorum approval is required.
### Editing sub-quorum details
Administrators may update a sub-quorum's name and description if circumstances change.
Tap **Rules**, then tap the three-dot menu next to the rule you want to edit and select **Edit rule**.
Tap the three-dot menu next to the sub-quorum you want to edit and select **Edit details**.
Update the **Sub-quorum name** or description as needed, then tap **Finish**.
Back in **Edit rule**, tap **Done**. Follow the prompts to submit biometric approval — quorum approval is required.
### Editing sub-quorum members
Tap **Rules**, then tap the three-dot menu next to the rule you want to edit and select **Edit rule**.
Tap the three-dot menu next to the sub-quorum, select **Edit members**, then update the selected members and tap **Continue**.
Back in **Edit rule**, tap **Done**. Follow the prompts to submit biometric approval — quorum approval is required.
### Editing sub-quorum approvals
Tap **Rules**, then tap the three-dot menu next to the rule you want to edit and select **Edit rule**.
Tap the three-dot menu next to the sub-quorum, select **Edit approval limit**, choose the number of required approvers, and tap **Save**.
Back in **Edit rule**, tap **Done**. Follow the prompts to submit biometric approval — quorum approval is required.
### Deleting a sub-quorum
Tap **Rules**, then tap the three-dot menu next to the rule you want to edit and select **Edit rule**.
Tap the three-dot menu next to the sub-quorum and select **Delete**.
Back in **Edit rule**, tap **Done**. Follow the prompts to submit biometric approval — quorum approval is required.
## Reset to default policy
You can reset a customized administrator policy back to the default configuration at any time.
Tap the policy you want to reset.
Select **Reset to default policy** and follow the prompts.
Select **Reset to default policy** again and confirm that you want to reset.
Tap **Finish and review** and follow the prompts to submit biometric approval — quorum approval is required.
## See also
For information about user roles and permissions, see [Permission levels](/knowledge-base/porto/users/permission-levels).
For detailed quorum configuration options, see [Quorum structures](/knowledge-base/porto/policies/quorums).
# Batch endorsements
Source: https://docs.anchorage.com/knowledge-base/porto/policies/batch-endorsements
Group multiple operations for combined approval and streamlined quorum requirements.
You're viewing **Porto** documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/users/overview)
Batch endorsements let you group multiple operations (withdrawals, transfers, or policy changes) together and submit them for a single combined approval instead of individual approvals. This streamlines workflow and can reduce approval overhead for repeated operations.
## What is a batch endorsement
A batch endorsement is:
* **A group of operations** — Multiple related transactions bundled together
* **Single approval** — All operations in the batch are approved together (not individually)
* **Reduced quorum** — Some organizations allow reduced approval requirements for batches
* **Atomic execution** — All operations in the batch execute together, or none do
You might batch:
* Daily withdrawals to multiple vendors
* Weekly stablecoin conversions
* Multiple policy adjustments
* Recurring transfers to trusted counterparties
## Eligible operations for batching
Not all operations can be batched. Typically eligible:
| Operation | Batchable | Notes |
| :-------------------------- | :-------- | :-------------------------------- |
| **Withdrawal** | ✔ | Most common batch operation |
| **Transfer between vaults** | ✔ | Internal transfers can be batched |
| **Stablecoin swap** | ✔ | Multiple swaps bundled |
| **Policy change** | ✔ | Limited — may have restrictions |
| **User management** | ✗ | Usually not batchable |
| **Vault settings change** | ✗ | Usually individual approvals |
Check with your administrator which operations your organization allows for batching.
## Create a batch endorsement
From your vault, select the asset and begin initiating a withdrawal or transfer.
During the operation flow, look for **Add to batch**, **Batch endorsement**, or **Group operations**. Tap it.
Select **Create new batch** or **Add to existing batch**. If new, name it (e.g., "Daily vendor settlements").
Enter the destination, amount, and other details for the first operation.
Tap **Add to batch** instead of **Submit for approval**. The operation is saved but not submitted.
Repeat the process for each additional operation you want to batch together.
Once you've added all operations, review the full batch to confirm all details.
Tap **Submit batch** or **Request approval**. The entire batch is submitted at once.
If you have approval permissions, complete biometric authentication to approve the full batch.
Operations in a batch must be compatible. You typically cannot mix different types (e.g., withdrawals and policy changes) in a single batch. Check your organization's batch policies for details.
## View pending batches
Go to the **Activity** section or **Pending approvals**.
Look for operations grouped as "Batch endorsement" or with a batch label.
Tap the batch to see:
* All operations in the batch
* Approval status of the batch
* Who submitted and who must approve
* Expected execution timeline
## Approving a batch
Go to **Activity** or **Pending approvals** and find the batch awaiting approval.
Expand the batch to see every operation. Verify:
* All destinations are correct
* All amounts are accurate
* No suspicious or unintended operations
If all looks correct, tap **Approve batch** or **Endorse**.
Complete Face ID or Touch ID to authorize approval of the full batch.
Once the batch has the required approvals, all operations execute in order.
Review every operation in a batch carefully. If even one operation is unintended or fraudulent, rejecting the entire batch may be necessary. There's no way to approve part of a batch — it's all or nothing.
## Rejecting a batch
If you spot an issue with any operation in a batch:
Find the pending batch in Activity or Pending approvals.
Identify which operation (or operations) is incorrect.
Select **Reject batch**, **Decline**, or **Refuse approval**.
You may be able to add a comment explaining why the batch was rejected.
The person who created the batch will be notified of the rejection and the reason.
The submitter can then fix the problematic operation and resubmit the batch.
## Editing a batch before submission
If you haven't submitted a batch yet, you can edit it:
Go to **Pending batches** or **Draft operations**.
Tap the batch you want to edit.
You can:
* Modify amounts or destinations in operations
* Remove operations from the batch
* Add new operations
Once edits are complete, tap **Submit batch** to send it for approval.
Once a batch is submitted for approval, individual operations cannot be edited. If you need to change something, the batch must be rejected and resubmitted.
## Batch execution
Once a batch has all required approvals:
1. **Operations execute in order** — Porto executes each operation sequentially
2. **All succeed or all fail** — If one operation fails, the entire batch may fail (depends on your setup)
3. **Activity log records all** — Each operation appears in Activity with batch timestamp
4. **Blockchain confirmation** — On-chain operations confirm at normal speeds
## Batching best practices
* **Group related operations** — Batch withdrawals to the same type of recipient (vendors, exchanges, etc.)
* **Reasonable batch size** — Don't batch hundreds of operations at once — keep batches to 5-20 operations
* **Clear naming** — Name batches so approvers understand their purpose ("Tuesday vendor payments," "Monthly stablecoin rebalancing")
* **Regular timing** — Create batches on predictable schedules if they're recurring (daily, weekly, monthly)
* **Verify before submission** — Review amounts and destinations carefully before submitting; rejection and resubmission is inconvenient
* **Document the batch** — Add notes explaining why operations are being batched together
## Batch approval policies
Your organization may have policies around batch approvals:
* **Batch approval thresholds** — Maximum total amount per batch
* **Reduced quorum** — Batches might require fewer approvers than individual operations
* **Frequency limits** — How often batches can be submitted
* **Recipient restrictions** — Batches to trusted destinations may have different rules than new addresses
Ask your administrator about your organization's batch endorsement policies.
## Troubleshooting batches
**Batch won't submit:**
* Ensure all operations are compatible
* Check that you have permission to batch these operation types
* Verify the total batch amount isn't exceeding organization limits
**Batch rejected:**
* Check the rejection reason from the approver
* Fix the problematic operation(s)
* Resubmit after making corrections
**Operation failed in batch:**
* Check Activity log to see which operation failed and why
* Resubmit just that operation individually, or fix and resubmit the batch
# Customizing admin policy
Source: https://docs.anchorage.com/knowledge-base/porto/policies/customizing-admin-policy
Configure approval requirements for administrative and user management changes.
You're viewing **Porto** documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/users/overview)
Admin policies control who can make administrative changes to your organization — like adding or removing users, changing user roles, and modifying vault settings. By customizing your admin policy, you ensure critical changes require appropriate oversight.
## What admin policy controls
Admin policies define approval requirements for:
* **User management** — Adding, removing, or changing user roles
* **Organization settings** — Changing organization name, contact info, etc.
* **Vault creation** — Creating new vaults (may require approval)
* **Security settings** — Enabling/disabling features, changing recovery options
* **Policy changes** — Modifying other policies themselves
* **Trusted destinations/counterparties** — Adding or removing pre-approved addresses
Not all operations require admin policy approval — see [Admin policies](/knowledge-base/porto/policies/admin-policies) for a complete list.
## Access admin policy settings
From the home screen, tap **Settings**.
Go to **Policies**, **Admin policy**, or **Administration**.
You'll see:
* Current approval requirements
* Who is designated as an approver
* Any quorum or multi-signature requirements
* When the policy was last modified
Select **Edit policy** or **Customize** to make changes.
## Customization options
### Single approver requirement
Require one designated approver for admin changes:
* **Simplest model** — One person (often the CEO or CFO) approves all admin changes
* **Speed** — Approvals are fast
* **Risk** — Less oversight if that person is unavailable or compromised
### Multi-approver (quorum) requirement
Require multiple approvers, such as 2 of 3 administrators:
* **More oversight** — Multiple people must approve critical changes
* **Security** — Harder for unauthorized changes to occur
* **Slower** — Takes longer to get approvals
* **Redundancy** — If one approver is unavailable, others can still approve
**Example:** "2 of \{CEO, CFO, Legal Officer}" or "All administrators must approve"
### Role-based requirements
Different requirements based on the change type:
* **Minor changes** — (e.g., updating contact info) may need 1 approver
* **User management** — (adding/removing users) may need 2 approvers
* **Critical changes** — (policy changes, security settings) may need all admins
## Create or edit admin policy rules
Go to **Settings** > **Policies** > **Admin policy**.
Select **Add rule** or **Create new policy**.
Specify:
* **What action** is this rule for? (user management, policy changes, vault creation, etc.)
* **Who can approve?** (specific users, roles, or groups)
* **How many approvers** are required? (1, 2, all, etc.)
* **Time window** for approval (how long until request expires)
For some operations, approval might depend on scope:
* Adding 1 user = 1 approver
* Adding 5+ users = 2 approvers
* Or based on role change level
Tap **Save** or **Create rule**.
Tap **Submit policy** or **Save changes**. Admin policy changes themselves may require approval.
If required by current admin policy, the change must be approved before taking effect.
## Admin policy templates
Your organization can choose from common templates:
### Centralized (single approver)
* **Approver:** CEO or designated administrator only
* **Use case:** Small teams, startup, strong trust in leader
* **Approval time:** Fast
* **Risk level:** Medium (depends on that person's availability and security)
### Distributed (2 of 3 required)
* **Approvers:** 3 administrators, any 2 can approve
* **Use case:** Mid-size organizations wanting checks and balances
* **Approval time:** Medium (faster than all-required, slower than single)
* **Risk level:** Low (requires consensus among multiple people)
### Consensus (all required)
* **Approvers:** All administrators must approve
* **Use case:** High-security orgs, joint custody, important decisions
* **Approval time:** Slow (depends on everyone's availability)
* **Risk level:** Very low (highest oversight)
## Role-based admin rules
You can set different rules by change type:
| Change | Rule | Approvers |
| :----------------------- | :--------------- | :---------- |
| **Update contact info** | 1 approver | Any admin |
| **Add new user** | 2 of 3 approvers | Admin group |
| **Remove user** | 2 of 3 approvers | Admin group |
| **Change user to Admin** | All approvers | All admins |
| **Modify admin policy** | All approvers | All admins |
| **Create new vault** | 2 of 3 approvers | Admin group |
Different changes can have different requirements based on sensitivity.
## Designating approvers
To change who can approve admin changes:
Go to **Settings** > **Policies** > **Admin policy**.
Select which users can approve (usually your admin team).
Choose how many approvers are required (1, 2, all, etc.).
Tap **Save**. Changes to admin policy itself may require approval.
All admins don't automatically get approval power — you must explicitly designate them as approvers in your policy.
## Approval timeouts
Admin policy changes require approval within a certain timeframe:
* **Typical timeout:** 24-72 hours
* **Shorter timeout:** Good for urgent situations (higher risk)
* **Longer timeout:** Good for less urgent matters (gives people time to review)
If an admin policy change isn't approved by the timeout, it expires and must be resubmitted.
## Common admin policy scenarios
**Scenario 1: Small team (3 people)**
* All are admins
* Policy: "All 3 must approve" admin changes
* Result: Highest security, slightly slower approvals
**Scenario 2: Medium organization (10 people, 3 admins)**
* Only 3 designated admins
* Policy: "2 of 3 admins must approve"
* Result: Faster than consensus, still multiple eyes
**Scenario 3: Large organization (100+ people, 5 admins)**
* 5 admins, some designated as "Super Admins"
* Policy: "For user add/remove: 1 super admin + 1 regular admin. For policy changes: all super admins"
* Result: Scalable, different levels of oversight
**Scenario 4: Distributed/DAO structure**
* 7 members in a decentralized organization
* Policy: "Any 4 of 7 members must approve admin changes"
* Result: Democratic, distributed approval
## Monitoring admin activities
Even though policy approvals control admin changes, you should still monitor:
1. **View audit log** — See all admin changes and who approved them
2. **Review user access** — Regularly verify who has access and their roles
3. **Check policy changes** — Ensure policies haven't been unexpectedly modified
4. **Monitor approvals** — See who's approving changes and when
This helps catch unauthorized or suspicious activities.
## Emergencies and exceptions
If your admin policy prevents necessary changes (e.g., all approvers are unavailable):
1. **Contact Porto support** — Explain the situation
2. **Provide verification** — Porto may verify your identity or ownership
3. **Emergency override** — In extreme cases, Porto may help with recovery
4. **Adjust policy afterward** — Consider policy changes to avoid future emergencies
Note: Emergency overrides leave an audit trail and should be rare.
## Best practices for admin policy
* **Require multiple approvers** — Especially for sensitive changes
* **Separate roles** — Different people should submit and approve changes
* **Document policy** — Record why your policy is structured this way
* **Review regularly** — Quarterly review of admin policy and approvals
* **Avoid single points of failure** — Always have backup approvers
* **Test the flow** — Make a low-risk change to ensure your policy works as expected
* **Communicate policy to admins** — All admins should know the approval requirements
# Customizing vault policies
Source: https://docs.anchorage.com/knowledge-base/porto/policies/customizing-vault-policies
Configure approval requirements and operational rules for individual vaults.
You're viewing **Porto** documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/users/overview)
Vault policies define approval requirements for operations within a vault — like deposits, withdrawals, transfers, and policy changes. Each vault can have its own customized policy, allowing different rules for different types of assets or business purposes.
## What vault policy controls
Vault policies define approval requirements for:
* **Deposits** — Receiving assets into the vault
* **Withdrawals** — Sending assets out of the vault
* **Transfers** — Moving assets between vaults
* **Stablecoin conversions/swaps** — If enabled
* **Policy changes** — Modifying the policy itself
* **User access** — Adding or removing users from the vault
* **Large transactions** — May have higher approval thresholds
See [Vault policies](/knowledge-base/porto/policies/quorums) for details on policy types and quorum structures.
## Access vault policy settings
From the home screen, select the vault you want to customize.
Tap the vault name or **Settings** icon.
Look for **Policies**, **Vault policy**, or **Rules**.
You'll see:
* Current approval requirements
* Quorum structure (who must approve)
* Any rules or thresholds
* When the policy was last modified
Select **Edit policy**, **Customize**, or **Modify rules**.
## Customization options
### Simple approval structure
Basic single or dual approval:
* **Single approver** — One designated approver for all vault operations
* **Two required** — Any two approvers must approve
* **All required** — Every approver must approve
### Advanced quorum structures
More complex approval rules:
* **Tiered by amount** — Different approvals for different transaction sizes
* **Role-based** — Different rules for different user roles
* **Time-based** — Different rules for certain times of day or days of week
* **Operation-type specific** — Different rules for withdrawals vs. transfers
### Risk-based rules
Adjust approvals based on risk:
* **Standard operations** — 1 approver needed
* **Large transactions** — (over \$X) 2 approvers needed
* **To new addresses** — (not pre-approved) 2 approvers needed
* **To trusted destinations** — (pre-approved) 1 approver needed
## Create policy rules
Go to **Settings** > **Policies** > **Vault policy**.
Select **Add rule**, **Create new rule**, or **Add condition**.
Specify when this rule applies:
* **Operation type:** Withdrawal, deposit, transfer, swap
* **Amount:** Any amount, or only above/below a threshold
* **Address type:** Any, trusted destination only, new address
* **User role:** Initiator, all users, etc.
Specify approval requirements:
* **Number of approvers:** 1, 2, all, etc.
* **Which approvers:** Specific roles, specific people, or any approver
* **Voting structure:** Simple majority, unanimous, etc.
How long before the approval request expires (default: 24 hours)
Tap **Save** or **Create rule**.
Tap **Save policy** or **Submit changes**. Vault policy changes may require admin approval.
If the vault has admin policy approval requirements, the change must be approved.
See [Adding rules](/knowledge-base/porto/policies/adding-rules) for detailed rule creation instructions.
## Quorum structures
Different vaults can have different quorum setups:
| Structure | Example | Best for |
| :--------- | :----------------------------------- | :--------------------------- |
| **1 of 1** | Treasury manager approves all | Small team, high trust |
| **1 of 3** | Any one of 3 approvers | Speed with distributed power |
| **2 of 3** | Any two of 3 approvers | Checks and balances |
| **3 of 3** | All 3 must approve | High security, joint custody |
| **2 of 2** | CEO + CFO must both approve | Executive oversight |
| **Tiered** | 1 approver for \<$100k, 2 for >$100k | Risk-adjusted |
Choose a structure that matches your organization's security needs and approval speed requirements.
## Vault policy templates
Common templates your organization may offer:
### Treasury Vault (High security)
* **Withdrawals:** 2 of 3 senior officers
* **Transfers:** 1 of 3 senior officers
* **Policy changes:** All 3 senior officers
* **Use case:** Large reserves, institutional customers
### Operations Vault (Standard security)
* **Withdrawals:** 1 operations manager + 1 approver
* **Transfers:** 1 approver
* **Policy changes:** 2 of 3 administrators
* **Use case:** Regular operations, moderate amounts
### Client Custody Vault (Flexible)
* **Deposits:** Any operator
* **Withdrawals:** Client + custodian approver
* **Transfers:** Client approval
* **Policy changes:** Custodian admin
* **Use case:** Client funds, specific approval controls
### Settlement Vault (Fast)
* **All operations:** 1 approver
* **Large transfers (>\$X):** 2 approvers
* **Policy changes:** Admin
* **Use case:** Frequent, regular operations, trusted parties
## Transaction amount thresholds
Set approval requirements based on transaction size:
Go to vault **Settings** > **Policies**.
Select **Add amount-based rule** or **Create tier**.
Set approval levels for different amounts:
* **Up to \$10,000:** 1 approver
* $10,001 - $**50,000:** 2 approvers
* **\$50,001+:** 3 approvers or Anchorage review
Tap **Save** and then **Submit policy changes**.
Thresholds can be by USD value, crypto amount, or both.
## Adding custom approvers
Designate specific users as approvers for a vault:
Go to vault **Settings** > **Users** or **Team**.
Select an existing user or add a new one.
Set their role to **Approver** or **Admin**.
Save the change. The user can now approve operations in this vault.
You can have different approvers in different vaults — for example, the CEO approves the treasury vault, but regional managers approve their respective vaults.
## Policy change requests
When you modify a vault policy:
1. **Submit for approval** — The policy change itself is submitted
2. **Approvers review** — Designated approvers review the new policy
3. **Approval required** — Usually requires the same quorum as the vault's own policy (or higher)
4. **Effective date** — Once approved, the new policy takes effect immediately
5. **Audit trail** — The change is recorded with who changed it and who approved it
## Monitoring policy effectiveness
After setting policies, monitor:
1. **Approval times** — Are approvals happening in reasonable time? If not, adjust approvers
2. **Rejection rates** — Are too many operations being rejected? Review the policy
3. **Bottlenecks** — Is one person always the bottleneck? Consider distributed approvers
4. **Compliance** — Is the policy still meeting your compliance requirements?
Review policies quarterly or when business changes.
## Emergency policy changes
If you need to change a vault policy urgently:
1. **Request expedited review** — Explain the urgency
2. **Temporary policy** — Sometimes you can implement a temporary policy and convert to permanent after review
3. **Escalation** — Contact your administrator or Porto account team for assistance
Emergency changes still require approval but may be fast-tracked.
## Special cases and exceptions
**Anchorage Digital review:**
* Large or unusual operations may require Anchorage Digital compliance review
* This is an automatic additional step; not affected by vault policy
* Typically takes 1-2 business days
**Unusual operations:**
* Operations to new addresses, bridges, or risky assets may have higher approval requirements
* Check your policy's rules for these scenarios
**Service agreements:**
* Enterprise customers may have negotiated policy terms with Anchorage
* These take precedence over default policies
## Testing your policy
Before fully relying on a new policy:
1. **Make a test operation** — Try a small withdrawal or transfer
2. **Verify approvals** — Confirm the right people are notified
3. **Check timing** — See how long approvals take
4. **Document learnings** — Note any issues to fix before next time
## Policy best practices
* **Balance security and speed** — More approvers = more security but slower operations
* **Right-size approvers** — Too few creates risk; too many creates bottlenecks
* **Clear thresholds** — Make amount-based rules obvious and well-documented
* **Separate roles** — Different people should submit and approve when possible
* **Document why** — Record the business reason for your policy structure
* **Review regularly** — Quarterly policy reviews catch issues early
* **Communicate** — All users should understand the policy and approval process
# Deleting rules
Source: https://docs.anchorage.com/knowledge-base/porto/policies/deleting-rules
Remove policy rules that are no longer needed.
You're viewing **Porto** documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/users/overview)
You can delete rules that are no longer necessary or that aren't being used. When you delete a rule, operations that would have matched that rule now match the next most-specific rule.
## When to delete rules
Consider deleting rules when:
* **Never used** — A rule hasn't matched any operations in months
* **Obsolete** — Business practice has changed and the rule no longer applies
* **Redundant** — Another rule covers the same scenario
* **Too complex** — A rule is causing confusion without clear benefit
* **Org restructure** — After staffing changes, a rule may no longer make sense
## Before deleting a rule
Before deleting, verify:
1. **Check recent operations** — Did this rule apply to any recent transactions?
2. **Confirm redundancy** — Is another rule covering the same scenarios?
3. **Impact analysis** — What operations will be affected by deleting this rule?
4. **Approval path** — Will deleting this rule speed up or slow down approvals?
5. **Compliance** — Does your compliance requirement depend on this rule?
## Delete a rule
Go to **Settings** > **Policies** > **Vault policy** or **Admin policy**.
Locate the rule you want to delete in the rules list.
Select **Delete rule**, **Remove**, or the **trash** icon.
You'll be asked to confirm you want to delete this rule. Review the rule one more time.
Some systems show which operations were matched by this rule — review to understand the impact.
Tap **Yes, delete** or **Confirm** to finalize.
Tap **Submit policy** or **Apply changes**. Rule deletion takes effect.
If your policy requires approval for policy changes, the deletion must be approved.
## What happens when you delete a rule
**Before deletion:**
* Withdrawal \$150,000 to new address
* Rule "Large withdrawals to new addresses" = 2 approvers
* Result: 2 approvers required
**After deleting that rule:**
* Same withdrawal \$150,000 to new address
* No longer matches the specific rule
* Now matches rule "Large withdrawals (any address)" = 1 approver
* Result: 1 approver required (faster approval)
Operations move to the **next-most-specific matching rule**. Every operation must match some rule — if you delete the last rule, a default rule must exist.
## Safe deletion practices
### Method 1: Replace, don't delete
Instead of deleting a rule, edit it to be less strict:
* **Before:** "Withdrawals > \$100k to new addresses" = 2 approvers (never used)
* **After:** Delete this rule
* **Better:** Edit rule to "Withdrawals > \$500k to new addresses" = 2 approvers (might capture some operations)
### Method 2: Stage the deletion
For important rules, delete in stages:
1. **Week 1:** Remove rule but keep it in draft state (visible but inactive)
2. **Week 2:** Monitor operations — do they route to other rules correctly?
3. **Week 3:** If no issues, permanently delete the rule
4. **Week 4:** Document the deletion
### Method 3: Create fallback rule first
Before deleting a specific rule, ensure a more general rule exists:
* **To delete:** "Withdrawals to untrusted counterparties" = 2 approvers
* **Fallback needed:** "All withdrawals" = 1 approver (catches what specific rule would have)
* **Then:** Delete the specific rule
## Common deletions
### Delete duplicate rules
You might have created rules that overlap:
**Duplicate rules:**
* Rule A: "Withdrawals > \$100k" = 2 approvers
* Rule B: "Large withdrawals" = 2 approvers (same threshold, same requirement)
**Action:** Delete one of them (keep the more specific one if conditions differ).
### Delete overly specific rules
Rules with very narrow conditions might never match:
**Example overly specific rule:**
* "Withdrawal of exactly \$73,452.50 on Tuesdays between 2 PM and 2:15 PM"
* (Probably never matches; delete it)
### Delete obsolete organization rules
After team restructuring, old rules might reference people who no longer work there:
**Obsolete rule:**
* "Requires approval from Bob and Alice"
* (Bob and Alice left; no one can approve; delete it)
## Fallback rule necessity
Every policy must have a **default/fallback rule** with no conditions. Before deleting any rule:
1. **Check if this is the default rule** — If yes, don't delete it unless replacing it
2. **Verify another rule will match** — Ensure operations won't fall through the cracks
3. **Test mentally** — Think through what rule would match if this one is deleted
## Testing before deletion
If possible, test the impact:
1. **Review recent operations** — See which rule each matched
2. **Simulate deletion** — Mentally trace operations through remaining rules
3. **Check no gaps** — Ensure every possible operation matches some rule
4. **Audit trail** — Review the history of what operations matched this rule
## Approval for rule deletion
Deleting rules requires the same approval process as policy changes:
* **Submitter:** The person proposing rule deletion
* **Approvers:** Usually the same policy that governs vault operations
* **Timing:** Deletion takes effect only after approval
* **Audit trail:** Deletion is recorded showing who approved it and when
## Recovering deleted rules
If you accidentally delete a rule:
1. **Check version history** — Some systems keep policy versions; you can roll back
2. **Recreate the rule** — If no backup, manually recreate it with the same conditions
3. **Request recovery** — Contact your administrator or Porto support for help
Keep documented copies of important rules in case you need to recreate them.
## Communication around deletions
When deleting an important rule, notify users:
1. **What's being deleted** — Name and purpose of the rule
2. **Why** — Business reason for the deletion
3. **Effective date** — When the deletion takes effect
4. **Impact** — How will this affect approvals? Faster or slower?
5. **Examples** — Show examples of operations affected
**Example notification:**
* "We're deleting the 'Small deposit' rule (1 approver for deposits under \$5k) because we'll require 1 approver for all deposits going forward."
* "Effective: Jan 15"
* "Impact: Small deposits will now match the default rule (1 approver), so no change."
## Audit trail of deletions
All rule deletions are recorded:
* **Who deleted it** — The user who made the deletion
* **When** — Exact time and date
* **Which rule** — All conditions and requirements of the deleted rule
* **Approval** — Who approved the deletion
* **Reason** — If provided, why the rule was deleted
This trail allows auditors to understand policy evolution.
## Rule deletion checklist
Before deleting a rule, verify:
* [ ] This rule hasn't been used recently
* [ ] Another rule covers similar scenarios
* [ ] No compliance requirement depends on this rule
* [ ] Users have been notified of the planned deletion
* [ ] A fallback rule exists to catch affected operations
* [ ] The deletion has been approved
* [ ] Audit trail shows the deletion
# Deleting subquorums
Source: https://docs.anchorage.com/knowledge-base/porto/policies/deleting-subquorums
Remove subquorums that are no longer needed.
You're viewing **Porto** documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/users/overview)
You can delete subquorums when they're no longer part of your approval structure. Before deleting, ensure another approval path exists for affected operations.
## When to delete a subquorum
Consider deleting a subquorum when:
* **No longer needed** — A subquorum is no longer part of your approval requirements
* **Replaced** — Another subquorum covers the same function
* **Organizational restructure** — After a major change, some subquorums become obsolete
* **Consolidation** — You're simplifying your approval structure
## Before deleting a subquorum
Before deletion, verify:
1. **Check current use** — Is this subquorum still referenced in any rules?
2. **Confirm replacement** — Does another subquorum or rule handle its purpose?
3. **Impact analysis** — What operations will be affected?
4. **Approval paths** — Will operations still have valid approval paths after deletion?
5. **Compliance** — Does your compliance requirement depend on this subquorum?
## Delete a subquorum
Go to **Settings** > **Policies** > **Vault policy**.
Locate the subquorum you want to delete.
Select **Delete subquorum**, **Remove**, or the **trash** icon.
If shown, review which rules or operations reference this subquorum.
You'll be asked to confirm. Review one more time.
Tap **Yes, delete** or **Confirm**.
If any rules referenced this subquorum, those rules may become invalid. You must fix them:
* Edit the rule to reference a different subquorum
* Delete the rule if it no longer makes sense
* Create a new subquorum if the purpose isn't covered elsewhere
Tap **Submit policy** or **Apply changes**.
If policy changes require approval, the deletion must be approved.
## What happens when you delete a subquorum
**Before deletion:**
* Rule: "Large withdrawals require (Finance AND Risk approval)"
* Finance = 2 of 3 CFO, Controller, Treasurer
* Risk = 1 of 2 VP Risk, Compliance Officer
* Withdrawal \$150k: Needs Finance + Risk approval
**After deleting Risk subquorum:**
* Rule is now incomplete: "Large withdrawals require (Finance AND ???)"
* Operation cannot proceed until rule is fixed
* Fix: Modify rule to "Large withdrawals require Finance approval only"
**Result:** Operations that relied on Risk approval no longer have that requirement.
## Handling orphaned rules
When you delete a subquorum, any rules using that subquorum become invalid. You must fix them:
### Option 1: Remove the reference
If a rule says "(Finance) AND (Risk)", and you delete Risk:
* Edit rule to just "(Finance)"
* Approvals now only need Finance group
### Option 2: Switch to another subquorum
If you delete Risk but want to replace it with a Compliance subquorum:
* Edit the rule from "(Finance) AND (Risk)" to "(Finance) AND (Compliance)"
* Approvals now need Finance + Compliance
### Option 3: Delete the rule entirely
If the rule no longer makes sense after deleting a subquorum:
* Delete the rule
* Operations revert to other matching rules
## Safe deletion practices
### Method 1: Move members first
Instead of deleting, move members to a different subquorum:
1. **Create new subquorum** — "Consolidated Approval"
2. **Add members** — Move all members from subquorum to be deleted
3. **Update rules** — Change rules to reference new subquorum
4. **Then delete** — Delete the old subquorum (now empty)
### Method 2: Verify no dependencies
Before deleting, confirm:
1. **Check all rules** — Are there any rules using this subquorum?
2. **Backup the structure** — Save the subquorum definition (in case you need to recreate it)
3. **Communicate first** — Notify affected approvers
### Method 3: Stage the deletion
Delete in phases:
1. **Week 1:** Remove subquorum from active rules (but don't delete it yet)
2. **Week 2:** Monitor — do operations route correctly without this subquorum?
3. **Week 3:** If no issues, delete the subquorum
4. **Week 4:** Document the deletion
## When NOT to delete a subquorum
Don't delete a subquorum if:
* **Still in use** — It's referenced by active rules
* **Compliance requires it** — Your regulatory obligations depend on it
* **No alternative path** — Deleting it would leave operations with no approval path
* **Recent creation** — You created it too recently to know if it's working
* **Historical significance** — You're maintaining it for audit purposes
Instead, consider [editing it](/knowledge-base/porto/policies/editing-subquorums) to remove active members while keeping the structure for historical records.
## Recovering a deleted subquorum
If you accidentally delete a subquorum:
1. **Check version history** — Some systems keep policy versions; roll back
2. **Recreate manually** — Remember the members and requirement, create it again
3. **Request recovery** — Contact your administrator or Porto support
Keep documented copies of important subquorum structures.
## Approval for subquorum deletion
Deleting a subquorum requires approval:
* **Approvers:** Based on your admin policy
* **Timing:** Deletion takes effect after approval
* **Audit trail:** Deletion is recorded with all details
## Communication around deletion
When deleting a subquorum, notify users:
1. **Which subquorum** — Name and purpose of the group being deleted
2. **Why** — Business reason for deletion
3. **Effective date** — When the deletion takes effect
4. **Impact** — Which approvals change? Are they faster or slower?
5. **New approval process** — If rules change, explain the new process
**Example notification:**
* "We're deleting the 'Risk Committee' subquorum (VP Risk + Compliance Officer)."
* "Reason: Consolidating approval requirements to streamline operations."
* "Effective: January 20"
* "New process: All withdrawals now require only Finance Committee approval (2 of 3)."
## Audit trail of deletion
Subquorum deletion is recorded with:
* **When:** Date and time deleted
* **Who:** User who requested deletion
* **Approval:** Who approved the deletion
* **Previous definition:** The full structure of what was deleted (subquorum name, members, requirement)
* **Reason:** Why it was deleted (if provided)
This allows you to reference the deleted structure later if needed.
## Simplifying complex structures
If you have many subquorums, consider simplifying:
**Before (complex):**
* 5 subquorums: Finance, Risk, Compliance, Legal, Operations
* Rules using combinations of all 5
**After (simplified):**
* 2 subquorums: Finance and Specialists (Risk + Compliance + Legal + Operations together)
* Simpler rules: Finance AND Specialists
**Actions:**
* Create Specialists subquorum with all specialist members
* Update rules to use simplified structure
* Delete the 4 individual specialist subquorums
**Result:** Simpler to manage, easier to understand.
## Best practices for subquorum deletion
* **Communicate early** — Notify users before deleting
* **Fix dependencies first** — Update or delete rules referencing the subquorum
* **Keep records** — Document what was deleted and why
* **Verify backups** — Ensure you have a way to recover if needed
* **Regular reviews** — Quarterly cleanup of unused or redundant subquorums
* **Simplify over time** — Use deletions as opportunity to simplify structure
* **One at a time** — Delete only one subquorum per change cycle for clarity
# Editing rules
Source: https://docs.anchorage.com/knowledge-base/porto/policies/editing-rules
Modify existing policy rules and update approval requirements.
You're viewing **Porto** documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/users/overview)
You can edit existing rules to change conditions, adjust approval requirements, or update thresholds as your organization's needs evolve.
## When to edit rules
Consider editing rules when:
* **Business needs change** — You handle larger or smaller transactions
* **Organization grows** — You hire more approvers or change roles
* **Thresholds need adjustment** — Amount limits are too high or low
* **Rules aren't working** — A rule is creating bottlenecks or isn't specific enough
* **Compliance changes** — New regulatory requirements necessitate policy changes
## Edit a rule
Go to **Settings** > **Policies** > **Vault policy** or **Admin policy**.
You'll see a list of all active rules. Rules are shown in priority order (most specific first).
Tap the rule you want to modify.
Select **Edit rule** or the **pencil** icon.
Modify any conditions:
* Operation type
* Amount thresholds
* Address types
* Time windows
* Initiator roles
Update:
* Number of approvers
* Which approvers (specific people or roles)
* Voting structure
* Approval timeout
Tap **Save** or **Update rule**.
Tap **Submit policy** or **Apply changes**. Modified rules take effect.
If your policy requires approval for policy changes, the edit must be approved.
## Common edits
### Adjust amount thresholds
If your transaction volume increases, you might adjust thresholds upward:
**Before:**
* Up to \$50,000: 1 approver
* $50,001 - $200,000: 2 approvers
* Over \$200,000: 3 approvers
**After:**
* Up to \$100,000: 1 approver
* $100,001 - $500,000: 2 approvers
* Over \$500,000: 3 approvers
Edit each rule to update the amount condition.
### Change approver requirements
If you add new approvers, you can adjust requirements:
**Before:** 2 of 2 (CEO + CFO) must approve large withdrawals
**After:** 2 of 3 (CEO, CFO, or COO)
Edit the rule to change the approver list and count.
### Make rules stricter
If security incidents increase approval requirements:
**Before:** 1 approver for deposits
**After:** 1 approver for deposits under $100k; 2 approvers for $100k+
Split the rule into two rules or add amount condition to existing rule.
### Make rules faster
If approvals are too slow, reduce requirements:
**Before:** 3 of 3 admins must approve transfers
**After:** 2 of 3 admins must approve transfers
Edit the rule to reduce from 3 to 2 approvers.
## Rule priority after editing
When you edit a rule that changes its specificity, rule priority may shift. For example:
**Original rule:** "Withdrawals > \$100k to new address" = 2 approvers
**After edit:** "Withdrawals > \$100k" = 1 approver (removed address condition)
Now the rule is less specific. If another rule says "Withdrawals to new address" = 2 approvers, that rule becomes more specific and takes priority for withdrawals over \$100k to new addresses.
**Solution:** Review all rules after editing one to ensure priority is what you intend.
## Editing without disruption
To edit a rule while minimizing disruption:
1. **Review affected operations** — See what operations the current rule applies to
2. **Create new rule** — Add a new rule with desired conditions
3. **Test the new rule** — Verify it works as expected
4. **Deactivate old rule** — Remove the old rule once new rule is working
5. **Audit trail** — The change is recorded showing old and new rules
## Before/after rule changes
Document the change:
| Rule | Before | After | Effective date |
| :---------------- | :--------------- | :--------------- | :------------- |
| Large withdrawals | 3 of 3 approvals | 2 of 3 approvals | Jan 15, 2026 |
Keep this record for compliance and future reference.
## Approval of rule changes
Rule edits themselves require approval:
* **Who approves:** Typically the same policy that governs vault operations
* **Timing:** Rule changes must be approved before taking effect
* **Notice:** Users should be notified of upcoming rule changes
## Testing rule changes
Before finalizing edits:
1. **Simulate operations** — Review how the new rule would apply to recent transactions
2. **Check for conflicts** — Ensure the edited rule doesn't conflict with other rules
3. **Verify priority** — Confirm the rule applies in the right order relative to other rules
4. **Calculate impact** — How many operations will be affected? Will approvals speed up or slow down?
## Rolling back edits
If an edited rule causes problems:
1. **Revert to previous version** — Many systems allow rolling back recent changes
2. **Create new rule** — Alternatively, create a new rule and deactivate the problematic one
3. **Notify users** — Let them know the rule has changed
4. **Document reason** — Record why the change was reverted
## Preventing rule conflicts
When editing rules, watch for conflicts:
**Conflict example:**
* Rule A (before edit): "Withdrawals > \$100k" = 2 approvers
* Rule B: "Withdrawals to trusted destinations" = 1 approver
* Edit Rule A to: "Withdrawals to new addresses" = 3 approvers
**Result:** For withdrawal >\$100k to new address, which rule applies?
* Rule A applies (more specific: amount + address + new)
* This is correct — highest specificity wins
**Solution:** Review rule priority after edits to ensure most specific rules still win.
## Communicating rule changes
When you edit rules, notify affected users:
1. **What changed** — Be specific about which rules were modified
2. **Why it changed** — Explain the business reason
3. **Effective date** — When does the new rule take effect?
4. **Impact** — How will this affect operations? Will approvals be faster/slower?
5. **Examples** — Provide examples of how operations are affected
## Audit trail of edits
All rule edits are recorded:
* **Who changed it** — The user who made the edit
* **When** — The exact time and date
* **What changed** — Detailed diff of conditions and requirements
* **Approval** — Who approved the rule change
Review the audit trail to understand rule evolution over time.
## Rule maintenance schedule
Establish a regular maintenance schedule:
* **Quarterly:** Review rules to ensure they still align with business needs
* **After incidents:** Review rules if security issues occur
* **After org changes:** Update rules when team structure or approvers change
* **After business changes:** Adjust thresholds if transaction volume changes significantly
See [Managing rules](/knowledge-base/porto/policies/managing-rules) for comprehensive rule maintenance.
# Editing subquorums
Source: https://docs.anchorage.com/knowledge-base/porto/policies/editing-subquorums
Modify subquorum membership and approval requirements.
You're viewing **Porto** documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/users/overview)
You can modify subquorums to add or remove members, adjust quorum requirements, or change how subquorums relate to each other (AND vs. OR logic).
## When to edit subquorums
Consider editing when:
* **Team changes** — Someone joins or leaves the approval group
* **Role changes** — Someone's role changes; they should no longer be an approver
* **Approval speed** — Current requirements are too strict or too lenient
* **Business changes** — Your business structure changes (merge, reorganization)
* **Redundancy** — You have overlapping or duplicate subquorums
## Edit a subquorum
Go to **Settings** > **Policies** > **Vault policy**.
Locate the subquorum you want to edit.
Select **Edit subquorum** or the **pencil** icon.
Add or remove members:
* **Add:** Tap **Add member** and select a user
* **Remove:** Tap **Remove** or **X** next to the member's name
Change how many approvers are needed:
* From: "2 of 3"
* To: "1 of 3" (faster) or "All" (stricter)
You can update the subquorum name (e.g., "Treasury Committee" → "Finance & Operations").
Tap **Save** or **Update subquorum**.
Tap **Submit policy** or **Apply changes**. The edited subquorum takes effect.
If policy changes require approval, the modification must be approved.
## Common edits
### Add a member
**Scenario:** New CFO joins; needs to be an approver.
**Action:**
1. Open Finance subquorum
2. Tap **Add member**
3. Select new CFO
4. Save changes
**Result:** New CFO is now part of the Finance subquorum; can approve operations.
### Remove a member
**Scenario:** Treasurer leaving; should no longer approve operations.
**Action:**
1. Open Finance subquorum
2. Find Treasurer in the member list
3. Tap **Remove**
4. Save changes
**Result:** Treasurer can no longer approve; approval quorum may adjust automatically.
### Adjust approval threshold
**Scenario:** Too many approvers required; approvals are slow.
**Before:** "3 of 5 Treasury Committee" **After:** "2 of 5 Treasury Committee"
**Action:**
1. Open Treasury Committee subquorum
2. Change requirement from "3 of 5" to "2 of 5"
3. Save changes
**Result:** Approvals now require only 2 instead of 3; faster process.
### Change subquorum relationship
**Scenario:** Subquorum logic should change.
**Before:** Finance AND Risk (both must approve) **After:** Finance OR Risk (either can approve)
**Action:**
1. Open vault policy
2. Find subquorum relationship section
3. Change from "AND" to "OR"
4. Save policy
**Result:** Operations now need approval from Finance OR Risk (not both).
## Member count adjustments
When you remove members, the quorum requirement may automatically adjust:
**Example:**
* **Before:** "2 of 3" members \{CFO, Controller, Treasurer}
* **Remove:** Treasurer
* **After:** Automatic adjustment to "2 of 2" (both CFO and Controller now required)
If this isn't what you want:
1. **Manually adjust the requirement** — Change "2 of 2" to "1 of 2" if that's preferable
2. **Or add a replacement member** — Add another treasurer to restore original structure
## Renaming subquorums
You can rename a subquorum for clarity:
**Before:** "SQ1" **After:** "US Signatories"
Renaming helps users understand the subquorum's purpose without changing its function.
## Editing subquorum logic
For complex structures, you might change how subquorums combine:
**Before:** (Finance) AND (Risk) AND (Legal)
* All three groups must approve
**After:** (Finance) AND ((Risk) OR (Legal))
* Finance must approve, and either Risk or Legal must approve
This is more flexible — you don't need all three groups, just Finance + one specialist.
## Impact analysis
Before finalizing edits, consider the impact:
**Questions to ask:**
1. Will this speed up or slow down approvals?
2. Are any approval paths now impossible?
3. Are any approvers now redundant?
4. Will users understand the new structure?
## Communicating subquorum changes
When you modify a subquorum, notify affected users:
1. **What changed** — Which subquorum and what specifically changed
2. **Why** — Business reason for the modification
3. **Effective date** — When does it take effect?
4. **Impact** — How does this affect approval processes?
5. **Examples** — Show an example of an operation under the new structure
**Example notification:**
* "We're removing the Assistant Treasurer from the Finance subquorum (still have CFO and Controller)."
* "This changes 'all 3 must approve' to '2 of 2 must approve' — approvals will be faster."
* "Effective: January 10"
## Approval for subquorum edits
Modifying subquorums requires the same approval as creating them:
* **Approvers:** Based on your admin policy
* **Timing:** Edit takes effect after approval
* **Audit trail:** Changes are recorded showing before/after state
## Rolling back edits
If an edit causes problems:
1. **Revert to previous state** — Some systems allow rolling back recent changes
2. **Manual reversion** — Edit again to restore previous settings
3. **Notify users** — Explain the reversion and why
Document the reversion in your audit trail.
## Documenting subquorum changes
Record changes over time:
| Date | Subquorum | Change | Reason | Approved by |
| :----------- | :-------- | :----------------------- | :--------------- | :---------- |
| Jan 10, 2026 | Finance | Removed Asst Treasurer | Departed company | CFO |
| Jan 5, 2026 | Risk | Added Compliance Officer | New hire | CEO |
| Dec 20, 2025 | Finance | Changed 3 of 3 to 2 of 3 | Speed approvals | Board |
This history helps you understand policy evolution.
## Best practices for editing subquorums
* **Make one change at a time** — Don't edit multiple subquorums simultaneously; hard to track impact
* **Test the impact** — Mentally trace operations through the new structure
* **Document the reason** — Record why the change was made
* **Communicate changes** — Notify all approvers of modifications
* **Review quarterly** — Check that subquorum structure still matches org structure
* **Keep it simple** — 3-4 subquorums is usually enough; more than that is hard to manage
* **Fallback paths** — Ensure there's always a way for operations to be approved, even if someone is unavailable
# Managing rules and policies
Source: https://docs.anchorage.com/knowledge-base/porto/policies/managing-rules
Overview of maintaining and monitoring your approval rules and policy structures.
You're viewing **Porto** documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/users/overview)
Managing rules and policies is an ongoing process. This guide covers best practices for keeping your policies effective, monitoring their impact, and updating them as your organization evolves.
## Understanding your current rules
Before managing rules, understand what you have:
Go to **Settings** > **Policies** > **Vault policy**.
You'll see a list of all active rules in priority order (most specific first).
For each rule, note:
* What conditions trigger it (operation type, amount, address, time, role)
* Who must approve
* How many approvers are required
* Approval timeout
Mentally trace where recent operations would match in this rule list.
Are there operations that don't match any rule? (They shouldn't be — default rule must exist)
## Regular rule reviews
Conduct quarterly reviews of your rules:
**Review checklist:**
* [ ] Are any rules never matching? (Consider deleting)
* [ ] Are any rules too broad? (Consider making more specific)
* [ ] Are any rules conflicting? (Overlapping conditions with different requirements)
* [ ] Do team members still understand the rules?
* [ ] Have business conditions changed? (Volume, asset types, counterparties)
* [ ] Are approval times acceptable? (Fast enough but still safe)
* [ ] Do team members know the approval process?
## Monitoring rule effectiveness
### Track approval metrics
Monitor how rules are performing:
* **Approval speed** — How long do approvals typically take?
* Target: Most approvals \< 2 hours
* Too slow: Consider reducing approver count or clarifying process
* **Rejection rate** — How often are operations rejected?
* Target: \< 5%
* Too high: Consider rules too strict or rejections are due to user errors
* **Escalation rate** — How often do operations require higher-level approval?
* Target: \< 10-15%
* Too high: Maybe your tiered thresholds are too conservative
* **Rule hit rate** — Which rules are matching operations?
* All rules should match something eventually
* Rarely-matching rules may be redundant
### Generate reports
Most systems allow you to view:
1. **Rule usage report** — Which rules matched how many operations last month?
2. **Approval timeline report** — How long did each operation take to approve?
3. **Rejection report** — What operations were rejected and why?
4. **Audit trail** — Who made changes to rules and when?
Review these monthly or quarterly.
## Identifying problem rules
**Signs of problematic rules:**
| Issue | Sign | Solution |
| :------------ | :------------------------------ | :-------------------------------------------- |
| Too strict | Approvals taking days | Reduce approver count or adjust thresholds |
| Too lenient | Rejection/incidents | Increase approver count or tighten conditions |
| Never matches | Rule never applies | Delete or adjust conditions |
| Too specific | Only applies once/month | Broaden conditions or merge with similar rule |
| Conflicting | Operations match multiple rules | Clarify priority or adjust conditions |
| Unclear | Users confused about approvals | Simplify and communicate better |
## Rule maintenance schedule
Establish a regular maintenance cadence:
| Period | Activity |
| :------------ | :------------------------------------------------------------- |
| **Weekly** | Monitor approval times; catch urgent issues |
| **Monthly** | Review rejection rates and escalations |
| **Quarterly** | Full rule review and audit; make updates as needed |
| **Yearly** | Comprehensive policy redesign review; document lessons learned |
## Updating rules
When updating rules, follow this process:
1. **Identify the issue** — What's not working about the current rule?
2. **Design the change** — How will you modify the rule?
3. **Announce the change** — Notify stakeholders
4. **Implement** — Make the change and submit for approval
5. **Monitor impact** — Track the new rule's effectiveness
6. **Document** — Record what changed and why
See [Editing rules](/knowledge-base/porto/policies/editing-rules) for detailed editing instructions.
## Policy simplification
Over time, policies can become complex. Simplify when possible:
**Signs of over-complexity:**
* More than 7-8 rules per policy
* Rules with 3+ conditions
* 5+ subquorums with nested logic
* Users confused about how to get approvals
**Simplification strategies:**
1. **Merge similar rules** — Combine rules with nearly identical requirements
2. **Remove duplicates** — If two rules do the same thing, delete one
3. **Consolidate subquorums** — Combine multiple specialized groups into broader categories
4. **Use default rule** — Remove overly specific rules; let broader rule apply
5. **Eliminate time-based rules** — These rarely add value and confuse users
**Example simplification:**
* **Before:** 10 rules covering different asset types, amounts, and times
* **After:** 3 rules: small transactions (1 approver), medium ($X-Y, 2 approvers), large (>$Y, 3 approvers)
## Approval process communication
Ensure users understand the process:
1. **Document the policy** — Create a simple guide showing rules and approval requirements
2. **Training** — New users should understand their approval responsibilities
3. **Visual flowchart** — Create a diagram showing decision tree for approvals
4. **FAQ** — Answer common questions about why certain operations require certain approvals
5. **Examples** — Show concrete examples of different operation types
**Example documentation:**
```text theme={null}
VAULT: Treasury
Simple operations (to trusted destinations): 1 approver needed
- Approver: Any of \{Treasurer, Assistant Treasurer\}
- Expected approval time: < 1 hour
Regular operations (to pre-approved addresses): 2 approvers needed
- Approvers: 2 of \{Treasurer, Assistant Treasurer, CFO\}
- Expected approval time: 2-4 hours
Large operations (> $500k or to new addresses): 3 approvers needed
- Approvers: All of \{Treasurer, CFO, CEO\}
- Expected approval time: 4-8 hours
```
## Handling policy exceptions
Sometimes operations need expedited or special approval:
1. **Escalation procedure** — How can someone request expedited approval?
2. **Emergency override** — What's the process if normal approvers aren't available?
3. **Temporary exceptions** — Can you temporarily change a rule for unusual situations?
4. **Appeal process** — What if someone disputes an approval decision?
Document these procedures so users know options.
## Policy evolution tracking
As rules change over time, maintain a changelog:
| Date | Rule | Change | Reason | Approved by |
| :------- | :------------------- | :--------------------------------------- | :--------------------------- | :---------- |
| Jan 2026 | Large transactions | Threshold raised $200k → $500k | Increased transaction volume | CFO |
| Dec 2025 | All operations | Added time-window exception for weekends | Speed end-of-week operations | CEO |
| Nov 2025 | Trusted destinations | Reduced from 2 to 1 approver | Streamline common operations | Board |
This history helps with compliance, auditing, and understanding why rules are structured as they are.
## Common policy scenarios
### Growing organization
As you grow, your approval structure should evolve:
1. **Stage 1 (startup):** 1-2 approvers for everything
2. **Stage 2 (20+ people):** Different approval tiers (small/medium/large)
3. **Stage 3 (100+ people):** Role-based approvals, department-specific rules
4. **Stage 4 (500+ people):** Complex subquorum structures with specialized functions
Each stage requires policy updates.
### High-compliance industry
If you're in a regulated industry (banking, healthcare, financial services):
* **Annual compliance audit** — Rules must be reviewed against compliance requirements
* **Regulatory alignment** — Ensure rules support compliance needs
* **Documentation** — Keep detailed records of policy changes and approvals
* **Training** — Users must understand policy and compliance implications
### Multi-geography organization
If you operate in multiple countries/regions:
* **Regional policies** — Different rules for different jurisdictions
* **Central oversight** — Corporate-level policies for cross-border operations
* **Local expertise** — Regional managers set policies for their area
* **Compliance** — Policies must meet all applicable regulations
### Multiple currencies or asset types
If you work with diverse assets:
* **Asset-specific rules** — Different approval requirements by asset type
* **Amount rules** — USD value thresholds vs. crypto amount thresholds
* **Custody** — Rules for custody assets vs. trading assets
* **Bridges and derivatives** — Special rules for higher-risk operations
## Getting stakeholder buy-in
When proposing policy changes:
1. **Document the rationale** — Why is the change needed?
2. **Show impact** — How will approvals change? Speed? Security?
3. **Get feedback** — Ask stakeholders (users, approvers, compliance, legal)
4. **Pilot if possible** — Test the change with a subset first
5. **Implement gradually** — Phase in major changes rather than big bang
6. **Monitor closely** — Watch the impact; adjust if needed
## Policy documentation template
Create a standard format for documenting policies:
```text theme={null}
POLICY NAME: [Name]
VAULT/ORGANIZATION: [Where it applies]
EFFECTIVE DATE: [When it starts]
LAST REVIEWED: [Date]
OWNER: [Person responsible]
PURPOSE:
[Why this policy exists; what risk it addresses]
RULES:
[List each rule with conditions and approval requirements]
SUBQUORUMS:
[If applicable, define each group and its quorum]
EXAMPLES:
[Show 2-3 example operations and their approval flows]
ESCALATION:
[How to handle exceptions or emergencies]
CHANGES FROM PREVIOUS VERSION:
[What was different; why it changed]
```
## Tools and automation
Some organizations use tools to help manage policies:
* **Policy management software** — Visualize rules, test impact
* **Approval workflow tools** — Automate routing and notifications
* **Audit logging** — Automatically track all rule changes
* **Analytics dashboards** — Monitor approval metrics
* **Template libraries** — Pre-built policies for common scenarios
Ask your administrator what tools are available.
## Best practices summary
* **Regular reviews** — Quarterly policy audits catch problems early
* **Clear documentation** — Users should understand why rules exist
* **Simplify over time** — Reduce complexity as you learn what works
* **Monitor metrics** — Track approval speed, rejection rates, escalations
* **Communicate changes** — Users should know about policy updates
* **Keep history** — Document why rules changed; helps with future decisions
* **One change at a time** — Don't modify multiple rules simultaneously
* **Involve stakeholders** — Get buy-in from approvers, compliance, users
* **Test before finalizing** — Simulate how new rules will affect operations
* **Maintain fallback** — Always have a default rule; never leave operations without an approval path
# Required approvers & sub-quorums
Source: https://docs.anchorage.com/knowledge-base/porto/policies/quorums
Configure required approvers and sub-quorums for vault and administrator policies.
You're viewing **Porto** documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/users/overview)
## Required approvers
Administrators may designate one or more required approvers for policies. Once changes are reviewed, submit biometric approval — quorum approval is required as determined by the administrator policy in place.
### Adding required approvers
Go to **Settings**, tap **Administrator policy**, then tap **Edit**.
Tap **Select required approvers**, add the required user, and tap **Save required user**.
Follow the prompts to complete the operation. Quorum approval is required as determined by the administrator policy in place.
### Editing required approvers (sub-quorum)
Administrators may define a sub-quorum from which a set number of approvals will be required for any operation.
Go to **Settings**, tap **Administrator policy**, then tap **Edit**.
Tap **Select required approvers** and save the required approvers.
Select the number of approvers required from the set of required approvers and tap **Next**.
Tap **Review and Submit** and complete biometric authentication. Quorum approval is required as determined by the administrator policy in place.
## Customizing vault policies
All operations in a vault follow the default policy unless you customize policies per operation type (governance, staking, or withdrawal). For each vault policy, you can:
Change base quorum members for a vault policy.
Edit the base quorum approval limit.
Add, edit, or delete sub-quorums within the vault policy.
Change sub-quorum members or edit sub-quorum approval limits.
Administrators with vault management permissions may customize vault policies as needed. Any changes are subject to quorum approval per the default administrator policy or vault management policy (if any).
### Navigating to vault policies
Tap **Settings**, then **Policies**, and select the vault policy you want to customize.
### Editing quorum members
Tap **Rules**, then tap the three-dot menu next to the rule you want to edit and select **Edit rule**.
In **Edit rule**, tap the **Quorum is** field, select the members who can approve operations under this rule, and tap **Continue**.
Tap **Done** to save the rule. Follow the prompts to submit biometric approval — quorum approval is required.
### Editing quorum approvals
Tap **Rules**, then tap the three-dot menu next to the rule you want to edit and select **Edit rule**.
In **Edit rule**, use the stepper under **Number of approvals required** to set how many quorum members must approve.
Tap **Done** to save the rule. Follow the prompts to submit biometric approval — quorum approval is required.
### Adding a sub-quorum
Sub-quorums establish a prerequisite, ensuring that an operation cannot be completed without a preset number of approvals from the sub-quorum members.
Tap **Rules**, then tap the three-dot menu next to the rule you want to edit and select **Edit rule**.
In **Edit rule**, tap **Add sub-quorum**.
From the base quorum's approver pool, select at least one member for the sub-quorum and tap **Continue**.
Set the number of approvals this sub-quorum requires and tap **Continue**.
Give the sub-quorum a name and an optional description, then tap **Finish**.
Back in **Edit rule**, confirm the new sub-quorum, then tap **Done**. Follow the prompts to submit biometric approval — quorum approval is required.
### Editing sub-quorum details
Tap **Rules**, then tap the three-dot menu next to the rule you want to edit and select **Edit rule**.
Tap the three-dot menu next to the sub-quorum you want to edit and select **Edit details**.
Update the **Sub-quorum name** or description as needed, then tap **Finish**.
Back in **Edit rule**, tap **Done**. Follow the prompts to submit biometric approval — quorum approval is required.
### Editing sub-quorum members
Tap **Rules**, then tap the three-dot menu next to the rule you want to edit and select **Edit rule**.
Tap the three-dot menu next to the sub-quorum, select **Edit members**, then update the selected members and tap **Continue**.
Back in **Edit rule**, tap **Done**. Follow the prompts to submit biometric approval — quorum approval is required.
### Editing sub-quorum approvals
Tap **Rules**, then tap the three-dot menu next to the rule you want to edit and select **Edit rule**.
Tap the three-dot menu next to the sub-quorum, select **Edit approval limit**, choose the number of required approvers, and tap **Save**.
Back in **Edit rule**, tap **Done**. Follow the prompts to submit biometric approval — quorum approval is required.
### Deleting a sub-quorum
Tap **Rules**, then tap the three-dot menu next to the rule you want to edit and select **Edit rule**.
Tap the three-dot menu next to the sub-quorum and select **Delete**.
Back in **Edit rule**, tap **Done**. Follow the prompts to submit biometric approval — quorum approval is required.
## Customizing administrator policies
All organization-level operations follow the default administrator policy unless administrators customize policies per operation type: User management, Trusted destination, Vault, and API management operations.
Any changes to administrator policies are subject to quorum approval according to the policy in place.
### Navigating to administrator policies
Tap the **Settings** icon, then tap **Admin policy** and select the policy to edit.
### Base quorum — editing members
Tap **Rules**, then tap the three-dot menu next to the rule you want to edit and select **Edit rule**.
In **Edit rule**, tap the **Quorum is** field, select the members who can approve operations under this rule, and tap **Continue**.
Tap **Done** to save the rule. Follow the prompts to submit biometric approval — quorum approval is required.
Other administrators will receive a notification to approve the action. Once quorum is met, Anchorage Digital will review the operation.
### Base quorum — editing approvals
Tap **Rules**, then tap the three-dot menu next to the rule you want to edit and select **Edit rule**.
In **Edit rule**, use the stepper under **Number of approvals required** to set how many quorum members must approve, then tap **Done**. Follow the prompts to submit biometric approval — quorum approval is required.
### Administrator sub-quorums — adding
Tap **Rules**, then tap the three-dot menu next to the rule you want to edit and select **Edit rule**.
In **Edit rule**, tap **Add sub-quorum**.
From the base quorum's approver pool, select at least one member and tap **Continue**. Set the number of required approvals and tap **Continue**.
Give the sub-quorum a name and an optional description, then tap **Finish**.
Back in **Edit rule**, tap **Done**. Follow the prompts to submit biometric approval — quorum approval is required.
### Administrator sub-quorums — editing details
Tap **Rules**, then tap the three-dot menu next to the rule you want to edit and select **Edit rule**.
Tap the three-dot menu next to the sub-quorum and select **Edit details**. Update the **Sub-quorum name** or description and tap **Finish**.
Back in **Edit rule**, tap **Done**. Follow the prompts to submit biometric approval — quorum approval is required.
### Administrator sub-quorums — editing members
Tap **Rules**, then tap the three-dot menu next to the rule you want to edit and select **Edit rule**.
Tap the three-dot menu next to the sub-quorum and select **Edit members**. Update the selected members and tap **Continue**.
Back in **Edit rule**, tap **Done**. Follow the prompts to submit biometric approval — quorum approval is required.
### Administrator sub-quorums — editing approvals
Tap **Rules**, then tap the three-dot menu next to the rule you want to edit and select **Edit rule**.
Tap the three-dot menu next to the sub-quorum, select **Edit approval limit**, choose the number of required approvers, and tap **Save**.
Back in **Edit rule**, tap **Done**. Follow the prompts to submit biometric approval — quorum approval is required.
### Administrator sub-quorums — deleting
Tap **Rules**, then tap the three-dot menu next to the rule you want to edit and select **Edit rule**.
Tap the three-dot menu next to the sub-quorum and select **Delete**.
Back in **Edit rule**, tap **Done**. Follow the prompts to submit biometric approval — quorum approval is required.
### Reset to default policy
Tap the policy you want to reset.
Select **Reset to default policy** and follow the prompts.
Select **Reset to default policy** again and confirm that you want to reset.
Tap **Finish and review** and complete biometric approval — quorum approval is required.
# Encrypted backups
Source: https://docs.anchorage.com/knowledge-base/porto/security/encrypted-backups
Enable encrypted backups of your Porto account data and recovery keys.
You're viewing **Porto** documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/users/overview)
Porto automatically backs up your account data and security keys in encrypted form. These backups allow you to recover your account and wallets if you lose your device or need to access your account from a new device.
## How backups work
**Automatic backups:**
* Porto automatically backs up your account data (vaults, wallet information, settings) after important changes
* Your encryption keys are also backed up securely
* Backups are encrypted end-to-end — Porto cannot decrypt them without your authentication
**Your role:**
* You don't need to manually trigger backups for account data
* You can optionally export recovery codes or keys for additional security
## Backup encryption
All backups are encrypted using:
* Your personal encryption key, derived from your Porto password
* Your device's secure enclave (Face ID or Touch ID authentication data)
* Industry-standard encryption protocols (AES-256)
This means:
* Only you and authorized devices can decrypt your backups
* Porto servers store encrypted backups but cannot access the data
* Your backups are useless without your authentication credentials
## Enable or verify backups
From the home screen, tap the **Settings** icon.
Navigate to **Security** or **Account security**.
Look for a **Backups** or **Recovery** section. You should see that automatic backups are enabled.
If not already enabled, set up Face ID or Touch ID. This allows encrypted backups to use your biometric data as part of the encryption scheme.
## What gets backed up
| Data | Backed up | Notes |
| :------------------ | :-------- | :----------------------------------------------------- |
| Account credentials | ✔ | Email and authentication state |
| Vault configuration | ✔ | Vault names, policies, users |
| Wallet information | ✔ | Wallet types, addresses, balance history |
| Keys and seeds | ✔ | Encrypted private keys and recovery seeds |
| Settings | ✔ | Preferences, notification settings, device preferences |
| Transaction history | ✔ | Activity log and past approvals |
| Biometric data | ✗ | Stored only on your device, not backed up |
## Recovery from backup
If you restore your account on a new device:
Enter your email and password on the new device.
Porto will detect your account has a backup and offer to restore it.
Complete identity verification (email code, security questions, or other methods your organization requires).
Your vaults, wallets, and settings will be restored to the new device.
Enable Face ID or Touch ID on the new device for secure transaction approval.
## Manual backup and export
For additional security, you can export your recovery codes or encryption keys:
From the home screen, tap **Settings**.
Go to the **Security** section.
Look for **Export recovery codes**, **Download keys**, or **Backup data**.
Complete biometric authentication or enter your password to authorize the export.
Download and save the backup file (usually a PDF or encrypted text file) to a secure location.
Keep the file in a secure place separate from your device — a safe, encrypted cloud storage, or printed and locked away.
Recovery codes and exported keys are sensitive — treat them like passwords. Anyone with these codes can potentially access your account. Store them securely and do not share them.
## Backup verification
To confirm your backups are current:
1. **Check backup status** — Go to **Settings** > **Security** and look for the backup timestamp
2. **Force a backup** — Sometimes making a change to your account (like updating a setting) triggers a backup update
3. **Test restoration** — On a test device, sign in and check that your vaults restore correctly
## Cloud backup location
Your encrypted backups are stored on Porto's secure servers. These servers:
* Use industry-standard encryption and security practices
* Are regularly audited for compliance
* Are distributed for redundancy and disaster recovery
For detailed information on Porto's security infrastructure, see [Key management](/knowledge-base/porto/security/key-management).
## Troubleshooting
**Backups not enabled:**
* Ensure you've signed in at least once on your current device
* Check that you have biometric authentication or a strong password set
* Go to **Settings** > **Security** and manually enable backups if available
**Can't restore from backup:**
* Confirm you're using the same email address as your original account
* Ensure you know your password (password resets are required before restoration)
* Contact your organization's administrator if restoration continues to fail
**Suspicious backup activity:**
* Check your backup timestamps to see if backups are occurring at expected times
* Review the devices associated with your account in **Settings** > **Devices**
* If you suspect unauthorized access, change your password immediately
# Key download preferences
Source: https://docs.anchorage.com/knowledge-base/porto/security/key-download-preferences
Control when and how you download private keys or recovery materials from Porto.
You're viewing **Porto** documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/users/overview)
Porto allows authorized users to download private keys, recovery seeds, and other sensitive recovery materials. Key download preferences let you control where downloads are allowed and add restrictions based on your organization's security policies.
## Why download keys
You might download keys for:
* **Backup security** — Keep a secure offline copy of your recovery materials
* **Emergency access** — Regain access to your wallets if Porto becomes unavailable
* **Wallet migration** — Move assets to another custody provider or self-custody
* **Compliance** — Some organizations require proof of key export for audit purposes
## Key download settings
From the home screen, tap **Settings**.
Navigate to **Security**, **Recovery**, or **Key management**.
Look for **Key download preferences**, **Export settings**, or **Recovery material downloads**.
You'll see:
* Whether key downloads are enabled for your account
* Restrictions (device type, network requirements, approval needs)
* Download history showing when keys were last exported
If your role allows it, you can modify who can download keys and what restrictions apply.
## Download restrictions
Your organization may have set restrictions on key downloads:
| Restriction | Meaning | Use case |
| :------------------------- | :---------------------------------------------------------------- | :----------------------------------------------------- |
| **Device-only** | Keys can only be downloaded to specific registered devices | High security — limit downloads to known devices |
| **Administrator approval** | Downloading keys requires an approver to authorize it | Compliance — audit trail of who accessed keys and when |
| **Network restrictions** | Keys can only be downloaded from certain IP addresses or networks | Security — prevent downloads from public Wi-Fi |
| **Time-based** | Downloads are only allowed during certain hours or days | Operational security — restrict to business hours |
| **One-time download** | Recovery materials can only be downloaded once | Maximum security — force users to store them safely |
If your organization has set restrictions, you'll see them listed in your key download settings.
## Download recovery materials
From the home screen, tap **Settings** > **Security**.
Look for **Download recovery codes**, **Export keys**, or **Backup recovery materials**.
You'll see what materials will be included:
* Recovery seed phrase (for wallet recovery)
* Private keys (for emergency wallet access)
* Account recovery codes
* Other sensitive materials
Confirm any restrictions are met (correct device, network, time of day).
If your organization requires approvals, submit a request and wait for an approver to authorize the download.
Tap **Authenticate** and complete Face ID or Touch ID to authorize the download.
The file will download as an encrypted PDF or text file. Save it to a secure location immediately.
Downloaded recovery materials are extremely sensitive. Anyone with access to these files can potentially access your wallets. Store them:
* In a safe or safety deposit box (printed copies)
* In encrypted cloud storage with strong authentication
* On an encrypted USB drive kept in a secure location
* Never share or screenshot these materials
## Temporary download allows
If your organization has strict download restrictions, you may be able to request temporary permission to download keys:
Go to **Settings** > **Key download preferences** and select **Request temporary download**.
Provide a reason for the download (backup, emergency, migration, etc.).
An approver will review and authorize your request. You'll be notified when approved.
If approved, you'll have a limited time window (usually 24-72 hours) to download your keys.
After the time window closes, the download permission automatically expires for security.
## Download history
You can view when recovery materials have been downloaded:
1. **Open settings** — Go to **Settings** > **Security** > **Key download preferences**
2. **View download log** — Check the "Download history" section to see:
* When downloads occurred
* Which user downloaded (if applicable)
* What materials were downloaded
* From which device or IP address
This audit trail helps you detect suspicious activity.
## Preventing unauthorized downloads
If key downloads are a security concern for your organization:
* **Enable approvals** — Require admin approval for all key downloads
* **Restrict to specific devices** — Only allow downloads from designated secure devices
* **Disable downloads entirely** — Some organizations turn off key downloads to prevent keys ever leaving the system
* **Time-based windows** — Allow downloads only during specific times when you can monitor activity
Contact your organization's administrator to configure these settings.
## If you need to download keys
If you need to download private keys or recovery materials:
1. **Check your permissions** — Confirm your role allows key downloads
2. **Verify restrictions** — Ensure you meet any organizational restrictions
3. **Request approval if needed** — Submit a request and wait for authorization
4. **Use a secure device** — Download to a trusted, secure device
5. **Store immediately** — Move the files to secure offline storage right away
6. **Delete from the device** — Remove the downloaded files from your device once stored
## Emergency access without keys
If you lose your recovery keys and need to access your wallets:
1. **Use Porto normally** — Your vaults and wallets remain accessible through the Porto app
2. **Request key restoration** — Ask your organization's administrator for help recovering keys
3. **Use the organization recovery document** — If available, this can help restore access
4. **Contact Porto support** — For technical assistance with account recovery
# Key management & recovery
Source: https://docs.anchorage.com/knowledge-base/porto/security/key-management
Manage wallet recovery shares, encrypted backups, and decrypt wallet keys.
You're viewing **Porto** documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/users/overview)
## Organization recovery document
The organization recovery document is used to restore your access to Porto by Anchorage Digital if you lose access to all Porto-enrolled devices. Store a copy in a location where it will not be lost or forgotten.
Anchorage Digital cannot restore your access if you lose your organization recovery document.
Unlike a seed phrase, the organization recovery document PDF is not sensitive material on its own — it is only relevant within Anchorage Digital's security architecture. Only a quorum of an organization's administrators can use it to initiate a recovery process.
You can back up additional copies of the organization recovery document at any time from **Settings > Recover access > Organization recovery document** in the Porto iOS app.
## Wallet recovery shares
Wallet recovery shares allow you to export your wallets outside of Porto if needed. You require 2 out of 3 recovery shares to access your wallet. A single wallet recovery share is not sensitive on its own.
With 2 out of 3 shares, your wallets become accessible outside of Porto. Maintain the separation and security of each wallet recovery share to safeguard your wallets against unauthorized access.
### Distributing wallet recovery shares
After onboarding, distribute each share to a different team member to keep them separate and secure. Once a wallet recovery share is distributed to a team member, it is sent to that team member's device — only that specific team member can access it on that device.
We highly recommend onboarding to Porto with at least 3 users to ensure proper distribution of wallet recovery shares.
### Backing up wallet recovery shares
If you have received one or more wallet recovery shares, you can back them up from **Settings > Recover access > Backup recovery shares** in the Porto iOS app, as long as you still have the original device you used to enroll in Porto.
## Encrypted wallet backups
Encrypted wallet backups are generated automatically with every wallet you create. They are not sensitive on their own and are accessible at any time from the web dashboard.
Encrypted wallet backups are required if you choose to access your wallets outside of Porto. To decrypt your wallet backups, you will need:
* 2 out of 3 wallet recovery shares
* A device enrolled in Porto **or** the organization recovery document
## Decrypting wallet keys
Administrators can access and decrypt encrypted private keys. A lead administrator must be elected and is responsible for scanning the required number of administrator QR codes to achieve quorum.
### Decrypting with an enrolled device
Go to **Settings** and tap **Decrypt private key**.
Retrieve your wallet PDF, elect a lead administrator, and tap **I'm ready to proceed**.
Scan the QR code in your wallet PDF.
Tap **I'm ready** again. A new QR code will be shown to all administrators, who must share their new QR code with the lead administrator for scanning.
The lead administrator must scan the required number of administrator QR codes as displayed on screen to achieve quorum.
Your private key will be decrypted once quorum is met.
### Decrypting with wallet recovery shares
Go to **Settings** and tap **Decrypt private key**.
Retrieve the encrypted wallet PDF and a quorum of wallet recovery dhares, then tap **I'm ready to proceed**.
Tap **Scan QR code** to initiate the operation. Scan the QR code on the encrypted wallet PDF and tap **Continue**.
Input a quorum of the wallet recovery share mnemonic phrases and tap **Validate** to finish decryption.
Be mindful of your surroundings when viewing your decrypted private key. Store it in a secure, offline location to ensure the safety of your funds.
# Organization recovery document
Source: https://docs.anchorage.com/knowledge-base/porto/security/org-recovery-document
Use your organization's recovery document to restore access to your account and vaults.
You're viewing **Porto** documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/users/overview)
An organization recovery document is a secure file that your Porto administrator may provide to help you recover your account and wallets in emergency situations. This document contains encrypted recovery credentials specific to your organization.
## What is an organization recovery document
The organization recovery document:
* Is created and managed by your organization's administrator
* Contains encrypted recovery seeds and keys for your vaults
* Is unique to your organization (not shared across customers)
* Requires your personal credentials to decrypt and use
* Is stored separately from your device and main backup systems
Not all organizations use recovery documents — ask your administrator if one is available for your account.
## When to use the recovery document
Use the recovery document when:
* You've lost access to all your devices
* You've forgotten your Porto password and cannot reset it
* You need to restore your wallets to a different custody provider
* Your organization's administrator instructs you to use it for account recovery
* Porto's standard recovery methods are unavailable
## Obtaining the recovery document
Contact your organization's Porto administrator or account manager. Ask for your "organization recovery document."
The document should come from your organization's official channels (email, secure delivery, in-person). Do not accept recovery documents from untrusted sources.
Once received, save the document in a secure location:
* A physical safe or safety deposit box (print the PDF)
* Encrypted cloud storage (not a regular folder or email)
* An encrypted USB drive kept in a secure location
Keep at least one additional copy in a different location for redundancy. For example:
* Original in a safe at home
* Copy in a safety deposit box at your bank
* Encrypted copy in a password-protected storage provider
The organization recovery document is extremely sensitive. Treat it like a password or private key. Do not:
* Share it with anyone
* Email it unencrypted
* Screenshot or take photos of it
* Post it online or in shared documents
* Store it in regular cloud storage without encryption
## Using the recovery document
If you need to use your recovery document to restore access:
Use a secure, private device or computer that you trust. Avoid public Wi-Fi networks.
Retrieve your recovery document from secure storage and open it. It will likely be a PDF file or encrypted file.
The document will contain:
* Organization recovery code or seed phrase
* Encrypted recovery keys
* Instructions specific to your organization
* A PIN or passphrase to decrypt the keys
Open Porto or visit the recovery URL provided in the document.
Follow the on-screen prompts to enter:
* Your email address
* Recovery code or seed phrase from the document
* Any additional verification information
Enter the PIN or passphrase included in the recovery document to unlock your wallet keys and account access.
Choose whether to:
* Restore to a new Porto account (for continued custody with Porto)
* Export keys to a self-custody wallet (to move assets elsewhere)
Confirm that your vaults and wallets have been restored with the correct assets and permissions.
## Updating the recovery document
Ask your organization's Porto administrator to provide an updated recovery document if:
* The original was lost or compromised
* You've added new vaults or assets since receiving it
* The PIN or credentials have changed
* Your organization has made security updates
The administrator can request a new document from Porto, which will include your current vaults and keys.
Securely destroy the old recovery document and store the new one in your secure location.
If you have copies in multiple locations, update all of them with the new document.
## What to do if the document is compromised
If you believe your recovery document has been lost, stolen, or accessed by unauthorized people:
1. **Notify your administrator immediately** — Contact your organization's Porto administrator or account manager
2. **Change your password** — Update your Porto password as soon as possible
3. **Review account activity** — Check your [Activity log](/knowledge-base/porto/assets/activity-history) for suspicious transactions
4. **Request a new document** — Ask your administrator to issue a new recovery document with fresh credentials
5. **Destroy the old document** — Securely delete or destroy the compromised copy
Your administrator may also:
* Rotate your account's encryption keys
* Reset your recovery credentials
* Flag your account for additional monitoring
## Emergency access without the recovery document
If your recovery document is unavailable:
1. **Try standard recovery** — Use the normal [Account recovery](/knowledge-base/porto/vaults-wallets/wallet-recovery) flow if you remember your password
2. **Use encrypted backups** — Porto's automatic backups may restore your account if you can verify your identity
3. **Contact administrator and support** — Both your organization and Porto's support team may be able to assist with recovery
4. **Alternative custody** — If Porto recovery is unavailable, discuss options with your administrator for accessing your assets through alternative methods
## Keeping your recovery document current
* **Update after major changes** — Request a new document if you add significant vaults or change your organization's structure
* **Check expiration dates** — Some recovery documents may have validity periods; ask your administrator about renewal
* **Test occasionally** — Some organizations periodically test recovery procedures to ensure documents are still valid
* **Communicate location** — Consider letting a trusted administrator know where you've stored the document (without giving them access to it)
## For administrators
If you're responsible for creating and managing recovery documents for your organization, see your organization's recovery management tools in the Porto admin dashboard.
# Recovering access
Source: https://docs.anchorage.com/knowledge-base/porto/security/recovering-access
Replace devices, reinstall the app, and recover organization access.
You're viewing **Porto** documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/users/overview)
## iPhone replacement
### Replacing with access to your old device
Use this method if you still have access to your old iPhone and can generate a QR code from it.
On your new device, tap your profile in the App Store, tap **Purchased**, then search for **Porto by Anchorage Digital** and install the app. Alternatively, search for **Porto by Anchorage Digital** directly in the App Store to re-download it.
On the old device, go to **Settings**, tap **Replace my device**, and follow the on-screen prompts to generate a QR code.
Open the Porto app on your new device and select **Join organization**. Scan the QR code displayed on your old device and follow the instructions.
Submit biometric authentication on the old device to initiate the operation.
Ask the administrators on the account to approve the replace device operation on their devices. Once quorum is met, the replacement will be complete.
### Replacing without access to your old device
Use this method if your old iPhone has been lost, stolen, or is otherwise inaccessible.
Contact [portohelp@anchorage.com](mailto:portohelp@anchorage.com) to initiate the device replacement operation. The old iPhone will be marked as lost.
After the device is marked as lost by the Porto Support team, an administrator on the account must go to **Settings**, then tap **Team**.
Tap **Lost device** next to the user's name, then tap **Set up new device**.
On your new device, tap your profile in the App Store, tap **Purchased**, search for **Porto by Anchorage Digital**, and install the app.
Only administrators can initiate and approve the replacement operation for a lost device.
## Reinstalling or updating the iOS app
If you are keeping the same Apple ID that was used to initially download Porto, a full reinstall is not required when switching to a new device — the app will appear in your purchased apps.
On your device, tap your profile in the App Store, then tap **Purchased**.
Search for **Porto by Anchorage Digital** and tap the download icon to install the app.
For assistance with device replacement or access recovery, contact [portohelp@anchorage.com](mailto:portohelp@anchorage.com).
# COSMOS staking
Source: https://docs.anchorage.com/knowledge-base/porto/staking/cosmos
Stake Cosmos ecosystem assets in Porto.
You're viewing **Porto** documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/users/overview)
## Introduction
Porto by Anchorage Digital supports custody and staking for a range of Cosmos ecosystem assets. Each network is secured using a proof-of-stake (PoS) consensus algorithm, allowing token holders to collect rewards for helping secure their respective networks.
Tendermint protocols refer to staking as "delegation." For the purposes of this guide, this functionality is referred to as staking.
## Supported Cosmos ecosystem assets
A layer-1 smart contract platform built on the Cosmos SDK. BLD holders can vote on proposed network changes and collect staking rewards.
A layer-1 blockchain and cross-chain communication platform enabling Web3 interoperability. AXL holders collect rewards for helping secure the network.
The economic center of the Cosmos ecosystem, providing interchain services to connected blockchains. ATOM holders collect rewards for helping secure the network.
An open decentralized finance platform. DYDX holders engage in on-chain staking and governance. Holders are encouraged to bridge their ethDYDX tokens to the new Cosmos SDK chain.
A layer-1 blockchain connected to the Cosmos ecosystem and interoperable with Ethereum. EVMOS holders collect rewards for helping secure the network.
A layer-1 PoS blockchain built on the Cosmos SDK for customized automated market makers. OSMO holders vote on proposed network changes and collect staking rewards.
A public, open-source PoS blockchain for financial services. HASH is the utility and governance token for Provenance Blockchain.
An open-source layer-1 blockchain for cross-chain identity and digital asset management. RMO holders collect rewards for helping secure the network.
An open-source layer-1 blockchain optimized for digital asset exchange. SEI holders collect rewards for helping secure the network.
Porto by Anchorage Digital offers the following for each supported Cosmos ecosystem asset:
* Custody your tokens (deposit and withdraw)
* Stake and unstake to any validator
* Claim rewards
## How to stake
Tap the vault and select your desired wallet.
Tap **Stake** and proceed to review and accept the disclosures. If applicable, select **Start auto-claim & stake rewards** to automatically claim and stake your rewards.
Enter the validator address you want to stake with, then enter the amount you would like to stake.
Tap **Review**, add a comment (optional), and follow the prompts to review and approve the operation. After quorum is met and required approvers have submitted their approval, Porto will review the operation.
## How to increase the staked amount
To increase your staked amount or stake to a different validator:
Go to the wallet screen and tap **View details**, then tap **Stake**.
Enter the validator address, add the amount you would like to stake, and tap **Review**.
Add a comment (optional) and follow the prompts to review and approve the operation. After quorum is met and required approvers have submitted their approval, Porto will review the operation.
## How to auto-claim and stake rewards
Go to the wallet screen.
Toggle **Auto-claim and stake rewards** on or off as applicable.
Rewards will be automatically claimed and staked every day. Gas fees will be deducted from the accrued rewards as set by network conditions. If rewards are insufficient to cover gas fees, the operation will fail.
Auto-claim and stake is not available for DYDX\_CHAIN.
## How to claim rewards
Go to the wallet screen and tap **View details** or **Claim rewards**.
Tap the three dots next to the validator that holds the rewards you want to claim and tap **Claim rewards**.
Enter the amount of rewards you would like to claim and tap **Next**.
Tap **Review**, add a comment (optional), and follow the prompts to review and approve the operation.
## How to unstake
Go to the wallet screen and tap **View details**.
Select the validator that holds the tokens you want to unstake and tap **Unstake**.
Enter the amount you would like to unstake and tap **Review**.
Add a comment (optional) and follow the prompts to review and approve the operation. After quorum is met and required approvers have submitted their approval, Porto will review the operation.
## Axelar (AXL) staking
Axelar is a layer-1 blockchain and cross-chain communication platform enabling Web3 interoperability. The network is secured using a PoS consensus algorithm, and Axelar's native token, AXL, allows holders to collect rewards for helping secure the network.
AXL staking follows the same stake, claim, and unstake flows described above. Use the validator address provided by your chosen Axelar validator when initiating staking.
For further questions, contact [portohelp@anchorage.com](mailto:portohelp@anchorage.com).
# ETH staking
Source: https://docs.anchorage.com/knowledge-base/porto/staking/eth
Stake Ethereum (ETH) in Porto.
You're viewing **Porto** documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/users/overview)
## Introduction
Ethereum is a layer-1 blockchain designed to enable decentralized applications. The network is secured using a proof-of-stake consensus mechanism, and its native token, ETH, allows token holders to collect rewards for helping secure the network.
Porto by Anchorage Digital offers support for Ethereum including:
* Custody your ETH (deposit and withdraw)
* Stake ETH to a dedicated validator and collect rewards
Staking operations can be initiated both in the iOS app and on the web dashboard.
## How to stake ETH
### Staking from iOS
Tap the vault that holds the ETH you would like to stake, then tap **ETH** to select the wallet.
Tap **Stake**, then tap **Continue** to review and accept the Ethereum staking disclosures.
Enter the number of validators you would like to fund and tap **Continue**.
Review the operation details and submit biometric approval.
### Staking from the web dashboard
Go to the vault on the web dashboard and select the ETH wallet.
Hover over the address field and click **Stake**.
Enter the number of validators you would like to fund and proceed to review the operation.
Review the operation details and click to submit biometric approval in the iOS app.
## Ethereum staking rewards
Rewards are automatically deposited into your Porto wallet (the wallet from which you staked).
For any validator with a balance greater than 32 ETH, the amount over 32 ETH will be routinely withdrawn to your available balance. This sweep occurs automatically approximately every five days.
## How to unstake ETH
Full staking withdrawals involve unstaking the full 32 ETH that was initially staked to a validator.
Unstaking is subject to an unbonding period determined by network conditions.
### Unstaking from iOS
From the vault page, tap **ETH** and select the wallet with your staked ETH.
Tap **Unstake**.
Enter the number of validators you would like to unstake and tap **Continue**.
Review the operation details and submit biometric approval.
### Unstaking from the web dashboard
Go to the vault on the web dashboard and select the wallet with your staked ETH.
Hover over the address field and click **Unstake**.
Enter the number of validators you would like to unstake and proceed to preview the operation.
Review the operation details and click to submit biometric approval in the iOS app.
## Frequently asked questions
**How do I claim my ETH rewards?**
No action is needed. Rewards are routinely withdrawn to your available balance automatically.
**How long does it take to unstake?**
A full staking withdrawal occurs in two parts:
1. **Exit the active validator set:** Once an exit request is made, the validator is added to the exit queue. With no other validators in the queue, this takes approximately 35 minutes. If other validators are queued, this can take several days—a maximum of 2,000 validators can exit per day.
2. **Withdraw balance to the execution layer:** Once exited, a validator must wait a minimum of 27 hours to be considered withdrawable. At that point, the exited ETH will be picked up in the next recurring withdrawal sweep, which runs on an approximately five-day cycle.
Given normal network behavior, you can expect a full staking withdrawal to take about one week on average.
For further questions related to ETH staking, contact [portohelp@anchorage.com](mailto:portohelp@anchorage.com).
# SOL staking
Source: https://docs.anchorage.com/knowledge-base/porto/staking/sol
Stake Solana (SOL) in Porto.
You're viewing **Porto** documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/users/overview)
## Introduction
Solana is a layer-1 blockchain designed to host decentralized applications. The network is secured using proof-of-stake consensus, and Solana's native token, SOL, allows token holders to collect rewards for helping secure the network.
Porto by Anchorage Digital offers support for Solana including:
* Custody your SOL (deposit and withdraw)
* Stake SOL to any validator and collect rewards
## How to stake SOL
Tap the vault and select the SOL wallet you would like to stake from.
Tap **Stake** and proceed to review and accept the disclosures.
Enter the validator address with which you would like to stake, then enter the amount you would like to stake.
Tap **Review**, add a comment (optional), and follow the prompts to review and approve the operation.
Adding more SOL to a wallet's existing staked position is not supported. If you would like to stake additional tokens, you must do so from a separate SOL wallet.
## Solana staking rewards
When you stake your SOL, the protocol automatically re-stakes your rewards. Rewards are distributed every epoch—approximately two-day periods—and will be added to your staking balance.
## How to unstake SOL
Go to the wallet screen and tap **View details**.
Select the validator from which you would like to unstake, then tap **Unstake**.
The wallet's entire staked balance with that validator will be unstaked. Review the amount of tokens to be unstaked.
Tap **Review**, add a comment (optional), and follow the prompts to review and approve the operation.
For questions about SOL staking, contact [portohelp@anchorage.com](mailto:portohelp@anchorage.com).
# SUI staking
Source: https://docs.anchorage.com/knowledge-base/porto/staking/sui
Stake SUI tokens in Porto.
You're viewing **Porto** documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/users/overview)
## Introduction
Sui is a layer-1 blockchain that is horizontally scalable to support the creation of rich and dynamic on-chain assets, while also offering instant settlement and high throughput. The network is secured using proof-of-stake consensus, and Sui's native token, SUI, allows token holders to collect rewards for helping secure the network.
Porto by Anchorage Digital offers support for Sui including:
* Custody your tokens (deposit and withdraw)
* Stake SUI to any validator and collect rewards
## How to stake SUI
Tap the vault and select the SUI wallet you would like to stake from.
Tap **Stake** to review and accept the disclosures.
Enter the validator address you want to stake with, then enter the amount you would like to stake.
Tap **Review**, add a comment (optional), and follow the prompts to review and approve the operation.
## How to unstake SUI
Go to the wallet screen and tap **View details**.
Select the validator from which you want to unstake and tap **Unstake**.
Enter the amount of tokens you would like to unstake and tap **Review**.
Add a comment (optional) and follow the prompts to review and approve the operation.
For questions about SUI staking, contact [portohelp@anchorage.com](mailto:portohelp@anchorage.com).
# Adding users with shared policies
Source: https://docs.anchorage.com/knowledge-base/porto/users/adding-users-advanced
Invite new users and assign them to existing vault policies.
You're viewing **Porto** documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/users/overview)
Only administrators can add new users to an organization and generate invites.
## Invite a new user
Tap the **Settings** icon, tap **Team**, then tap **Add new user**.
Select the permission level for the user, then tap **Continue**.
Select the vault policies the user will have access to, then tap **Continue**.
Adjust the permissions for each selected policy, then tap **Continue**.
Provide the email address of the user you would like to invite.
## Next steps for a new user
The new user will receive an invite via email from `institutional@messages.anchorage.com` with instructions for how to join the organization. They'll need to download the Porto iOS app from the App Store first.
In the invite email, tap **Download the Porto iOS app** to download the mobile app.
## Initiator and quorum approvals
Once the new user completes enrollment, the operation moves to quorum approval.
The administrator who initiated the request receives an alert to approve the operation.
Quorum administrators receive a notification to approve the **Add user** operation.
Tap **Add user** and complete biometric authentication to confirm.
# Managing users
Source: https://docs.anchorage.com/knowledge-base/porto/users/managing-users
Change permission levels and remove users from Porto.
You're viewing **Porto** documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/users/overview)
Administrators with vault management permissions may adjust user permission levels and remove users from the organization.
## Changing permission levels
### Assigning vault access as an Operator
Administrators can add users to a vault and assign them Operator-level privileges to initiate operations, or to both initiate and approve vault operations.
Tap the desired vault, then tap the **Settings** icon in the upper right corner, then tap **Users**.
Tap **Add user** and select the user or users to add to the vault.
To restrict a user to initiate-only permissions, tap the user, select **Initiate only**, and tap **Save changes**.
Tap **Finish and review**, add an optional comment, and follow the prompts to submit biometric approval. The other administrators will receive a notification to approve. Once quorum is met, the operation will be completed.
### Assigning users as administrators
Administrators can increase or decrease a user's permissions to the administrator level by editing the administrator policy's base quorum.
Tap the **Settings** icon, then tap **Admin policy** and select the policy to edit.
Tap **Rules**, then tap the three-dot menu next to the rule you want to edit and select **Edit rule**.
In **Edit rule**, tap the **Quorum is** field, select the user or users to add, then tap **Continue**.
Tap **Done** to save the rule, then follow the prompts to submit biometric approval — quorum approval is required.
The other quorum administrators will receive a notification to approve the operation. Once quorum is met, the operation will be completed.
## Removing users
Only administrators with user management permissions can remove users from the organization.
Tap the **gear icon** to open Settings, scroll down, and tap **Team**.
Select the user you want to remove.
Tap **Remove user from organization**, add an optional comment, and tap **Review**.
Submit biometric approval. The other administrators will receive a notification to approve the operation. Once quorum is met, Anchorage Digital will review for final approval.
# Permission levels
Source: https://docs.anchorage.com/knowledge-base/porto/users/permission-levels
Understand role-based permissions and what each user role can do.
You're viewing **Porto** documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/users/overview)
Porto uses role-based access control. Each user has a role that defines what they can do in the system. Roles can be different at the organization level and within individual vaults, allowing fine-grained control over permissions.
## Organization-level roles
When you're invited to a Porto organization, you're assigned an organization role. This role determines your base permissions across all vaults.
| Role | Organization permissions | Vault access |
| :------------ | :------------------------------------------- | :------------------------------------------ |
| **Viewer** | View organization structure, settings, users | View vaults and assets (no actions) |
| **Operator** | Create receive addresses, request deposits | Same as Vault Operator |
| **Initiator** | Initiate transfers and withdrawals | Same as Vault Initiator |
| **Approver** | Approve operations from others | Approve quorum requirements |
| **Admin** | Full access to all settings and users | Full vault control, can modify all policies |
## Vault-level roles
Within individual vaults, you can have a different role than your organization role. This allows more granular permission management.
| Role | Vault permissions | Can approve | Can initiate |
| :------------ | :----------------------------------------- | :---------- | :----------- |
| **Viewer** | View vault details, assets, activity | — | — |
| **Operator** | Create deposit addresses, request deposits | — | — |
| **Initiator** | Initiate transfers and withdrawals | — | ✔ |
| **Approver** | Approve operations in this vault | ✔ | — |
| **Admin** | Full vault control | ✔ | ✔ |
## What each role can do
### Viewer
**Can:**
* View all vaults you're added to
* View vault details (name, balance, users, policies)
* View asset balances and transaction history
* See pending operations and approvals
**Cannot:**
* Initiate any operations
* Approve operations
* Create deposit addresses
* Modify any settings
**Best for:** Auditors, observers, compliance staff who need read-only access.
### Operator
**Can:**
* View vault details and balances
* Create new deposit addresses
* Request incoming transfers/deposits
* View Activity and approvals
**Cannot:**
* Initiate outgoing transfers or withdrawals
* Approve operations
* Modify vault settings
**Best for:** Treasury team members, account coordinators who work with incoming assets.
### Initiator
**Can:**
* Do everything Operator can do
* Initiate transfers (between vaults)
* Initiate withdrawals (to external addresses)
* Initiate stablecoin swaps
* Request Anchorage review for large transfers
**Cannot:**
* Approve operations (unless they're also an Approver)
* Modify vault policies or user permissions
* Change vault settings
**Best for:** Operations team, trading staff who initiate movements.
### Approver
**Can:**
* Approve operations initiated by Initiators
* View pending approvals and operations
* See approval history
* Provide comments on approvals
**Cannot:**
* Initiate operations
* Modify vault settings
* Add or remove other users
**Best for:** Risk officers, compliance reviewers, senior management.
### Admin
**Can:**
* Do everything (all permissions)
* Manage users (add, remove, change roles)
* Modify vault and admin policies
* Configure quorum and approval rules
* Access vault recovery and security features
* Export activity and reports
**Best for:** Vault owners, account managers, senior leadership.
## Role separation principle
The **principle of least privilege** suggests:
* Give each user only the minimum permissions they need
* Separate the "initiator" and "approver" roles — don't give both to the same person
* This prevents unauthorized operations and reduces fraud risk
**Example structure:**
* Treasurers = **Initiators** (they request operations)
* Finance managers = **Approvers** (they review and approve)
* Compliance = **Viewers** (they audit)
* One executive = **Admin** (oversees everything)
## Organization role vs. vault role
Your permissions are the **most restrictive** of:
* Your organization role
* Your vault-specific role
**Example:**
* You're a Viewer at the organization level
* But you're an Initiator in Vault A
* **Result:** You can only View other vaults, but can Initiate in Vault A
This allows organizations to give elevated permissions for specific vaults without granting them organization-wide.
This vault-level flexibility applies to permissions, not visibility. Today, any user added to the organization can see activity across every vault, regardless of their organization or vault-specific role — an Operator, a Viewer, and an Admin all have the same visibility into org-wide activity. Vault-level visibility gating is coming soon.
## Permission matrix
Complete permission matrix across all operations:
| Action | Viewer | Operator | Initiator | Approver | Admin |
| :---------------------- | :----- | :------- | :-------- | :------- | :---- |
| **View vault/assets** | ✔ | ✔ | ✔ | ✔ | ✔ |
| **View activity** | ✔ | ✔ | ✔ | ✔ | ✔ |
| **Request deposit** | — | ✔ | ✔ | — | ✔ |
| **Initiate withdrawal** | — | — | ✔ | — | ✔ |
| **Initiate transfer** | — | — | ✔ | — | ✔ |
| **Approve operation** | — | — | — | ✔ | ✔ |
| **Add user** | — | — | — | — | ✔ |
| **Remove user** | — | — | — | — | ✔ |
| **Modify policy** | — | — | — | — | ✔ |
| **Change user roles** | — | — | — | — | ✔ |
## Checking your permissions
From the home screen, tap **Settings**.
Go to **Users**, **Team**, or **People**.
Look for your user profile in the list.
You'll see:
* Your organization role
* Your vault-specific roles (if different)
* When you were added
* Your status (active, pending, etc.)
## Requesting role changes
If you need different permissions:
1. **Talk to your administrator** — Explain why you need the permission change
2. **Get approved** — Your admin will review and approve the change
3. **Role updates** — Your new role takes effect immediately
4. **Verify access** — Check your settings to confirm the new role is active
Role changes are tracked in your Activity log for compliance.
## Common role scenarios
**Team member getting access to new vault:**
* Admin creates them as an Initiator in the new vault
* They keep their Operator role in other vaults
* They can initiate in new vault, but only operator permissions elsewhere
**Promoting someone to approver:**
* Admin changes them from Initiator to Approver
* They can now approve operations
* They can no longer initiate (unless they're an Initiator + Approver both)
**Limiting someone's access:**
* Admin removes them from a vault or changes them to Viewer
* They retain other roles in other vaults
* Changes take effect immediately
## Best practices for role management
* **Regular audits** — Review user roles quarterly to ensure they still match job functions
* **Principle of least privilege** — Always start with the minimum role needed
* **Separate roles** — Keep initiators and approvers separate when possible
* **Document changes** — Record why role changes were made for compliance
* **Onboarding checklist** — New team members should be set up with correct roles from day one
* **Off-boarding** — Remove or disable accounts immediately when someone leaves
## Next steps
To configure approval rules for operations based on roles, see [Policies & approvals](/knowledge-base/porto/policies/admin-policies).
For instructions on managing users and changing permissions, see [Managing users](/knowledge-base/porto/users/managing-users).
# Removing a user
Source: https://docs.anchorage.com/knowledge-base/porto/users/remove-user
Remove team members from your organization or specific vaults.
You're viewing **Porto** documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/users/overview)
You can remove users from your Porto organization or from specific vaults. Removing a user revokes their access to the account while preserving the audit trail of their previous activities.
## Before removing a user
Before you remove someone, consider:
* **Pending approvals** — Are they waiting to approve an operation? Get approvals completed first
* **Operations in progress** — Are they in the middle of any operations? Let them finish
* **Off-boarding workflow** — Use your organization's standard off-boarding procedure
* **Reason documentation** — Record why the user is being removed for compliance
## Remove from organization
Removing a user from the organization revokes all their access immediately.
From the home screen, tap **Settings**.
Go to **Team**, **Users**, or **Participants**.
Tap the user you want to remove. You can search by name or email.
Select **Remove user**, **Remove from organization**, or **Delete**.
You'll be asked to confirm that you want to remove this user. Review their name and email to ensure it's correct.
Some organizations allow or require you to note why the user is being removed (e.g., "Left company," "Transferred to different team").
If your policies require it, submit the removal for administrator approval.
Complete Face ID or Touch ID to authorize the removal. This is a sensitive action.
User removal cannot be undone. Once removed, they lose all access and must be re-invited to regain access. Their historical activity remains in the audit trail permanently.
## Remove from specific vault
If you want to keep a user in your organization but remove their access to a specific vault:
Go to the vault and tap **Settings**.
Tap **Users**, **Team**, or **Participants**.
Select the user you want to remove from this vault only.
Select **Remove from vault**, **Revoke access**, or **Delete**.
Verify that you're removing them from this specific vault (not the organization).
Depending on your policies, this may require vault policy approval.
Complete Face ID or Touch ID to authorize.
The user retains access to all other vaults and the organization; they're only removed from this specific vault.
## After removal
When a user is removed:
**Immediate effects:**
* Their session is ended — they're logged out of all devices
* Their API keys or access tokens become invalid
* They can no longer see vaults or assets
* Pending approvals they hadn't completed are cancelled
**What persists:**
* All their historical activity remains in the audit trail
* Past approvals they provided are recorded with their name
* Transaction history shows their involvement
* Compliance records remain intact
**What they keep:**
* They can request a copy of their activity history if needed
* Their historical transactions and approvals are unchangeable record
## Removing admins
If you need to remove an admin user:
* **Ensure there's another admin** — You must always have at least one active admin
* **Transfer ownership** — The admin may need to transfer vault ownership before removal
* **Get another admin's approval** — Removing an admin often requires approval from another admin
* **Off-boarding procedure** — Your organization may have specific admin off-boarding steps
Contact your account manager if you need to remove your last remaining admin.
## Removing yourself
If you accidentally remove yourself from an organization or vault:
1. **Contact another admin** — An admin must re-invite you
2. **Provide your email** — Give them the email associated with your Porto account
3. **Accept re-invitation** — You'll receive an invitation to rejoin; accept it
4. **Set up security** — Re-enable biometric authentication and other security settings
If you're the last admin and remove yourself, you've locked yourself out. Contact Porto support for recovery.
## Reactivating a removed user
If you need to give someone access again after removal:
1. **Invite them again** — Use the standard [add participant](/knowledge-base/porto/getting-started/setup-participants) or [add user to vault](/knowledge-base/porto/vaults-wallets/vaults) process
2. **Assign role** — Choose their role (Viewer, Operator, Initiator, Approver, Admin)
3. **Add to vaults** — Select which vaults they should access
4. **Send invitation** — They'll receive a new invitation and must accept it
Their old activity remains in the audit trail even after re-invitation.
## Compliance and audit trail
User removals are tracked for compliance:
**Recorded in audit trail:**
* When the user was removed
* Who requested the removal
* Who approved (if approval was required)
* Any reason provided
* Their final status before removal
**For regulatory purposes:**
* All user access changes are logged
* Removal dates are recorded per user
* Historical approvals from removed users are timestamped
* Activity remains auditable even after removal
## Role change as alternative
Before removing a user, consider whether **changing their role** might be better:
| Scenario | Better option |
| :-------------------------------- | :-------------------------------------------------- |
| Someone shouldn't approve anymore | Change to Operator instead of removing |
| Someone should only view | Change to Viewer instead of removing |
| Someone left temporarily | Change to Viewer instead of removing |
| Someone left permanently | Remove them |
| Someone changed departments | Change vault access instead of organization removal |
Role changes are reversible; removal is permanent.
## Best practices for removing users
* **Follow off-boarding** — Use your organization's standard procedure
* **Coordinate timing** — Remove access right at the end of their work day
* **Revoke credentials** — If they had generated API keys, revoke those first
* **Notify security** — Let your security team know when accounts are deactivated
* **Document reason** — Keep records of why users were removed
* **Verify permissions** — Confirm you have admin permissions before attempting removal
* **Check for pending work** — Don't remove someone mid-approval or mid-transaction
# Creating a vault with shared policies
Source: https://docs.anchorage.com/knowledge-base/porto/vaults-wallets/creating-vault-advanced
Create a vault using existing shared policies or configure a new policy.
You're viewing **Porto** documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/users/overview)
Administrators can create as many vaults as needed for the organization. When creating a vault, you can reuse an existing vault policy to apply the same approval rules, users, and permissions already configured on other vaults—or create an entirely new policy for this vault.
## Select an existing vault policy
Selecting an existing policy lets you reuse the same quorum rules, users, and permissions configured on other vaults. Any future changes to that policy will apply to all vaults assigned to it.
### On iOS
Scroll down and tap **Create new vault**. Enter the vault name and description, select the account, then tap **Continue**.
Select **Use an existing vault policy** and choose the policy you want to apply. Tap **Continue** to proceed.
Add a comment (optional), review the operation details, then follow the prompts to submit biometric approval. Administrators with vault management permissions will be notified to approve the vault creation. Anchorage Digital will review and finalize the operation, making the vault visible.
### On the web dashboard
Select the existing policy you want to assign to this vault, then select **Next**.
Add a comment (optional), then select **Finish and review**. Use the iOS app to submit biometric approval — quorum approval is required.
## Create a new vault policy
Creating a new vault policy builds an entirely new configuration of users, permissions, and approval rules specifically for this vault. Once approved, you can also assign this policy to other vaults.
### On iOS
Scroll down and tap **Create new vault**. Enter the vault name and description, select the account, then tap **Continue**.
Select **Create a new vault policy**, then tap **Continue**.
Add a group of users with permission to initiate only, or to initiate and approve operations—such as default, governance, staking, or withdrawal operations. A minimum of 3 users should have initiate and approve permissions.
Add rules to specify which users must approve a given operation type. By default, all operations requiring quorum follow the **Any vault operation** rule's quorum and sub-quorum(s). You can add new rules for specific operation types to override this. For details on configuring rules, see [Managing rules](https://docs.porto.xyz/docs/managing-rules).
Add a comment (optional), review the operation details, then follow the prompts to submit biometric approval. Administrators with vault management permissions will be notified to approve the vault creation. Anchorage Digital will review and finalize the operation, making the vault visible.
### On the web dashboard
Select **Create new vault policy**. Add at least 3 members who can initiate and approve operations, then select **Next**.
Define the rules for which approvals are needed per operation type, with a minimum of 2 approvers per rule. In this step, you can:
* Set a base quorum and sub-quorums per policy rule.
* Add rules to adjust the approval requirements for specific operation types.
Enter a name for the new vault policy. Once approved, you can assign it to new or existing vaults, which will inherit its users, permissions, and approval rules.
Add a comment (optional) and preview the changes. Select **Finish and review**, then use the iOS app to submit biometric approval — quorum approval is required.
# Vaults, wallets & addresses
Source: https://docs.anchorage.com/knowledge-base/porto/vaults-wallets/overview
Create and manage vaults, wallets, and deposit addresses in Porto.
You're viewing **Porto** documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/users/overview)
## Vaults
Use multi-asset vaults to organize your assets. Vaults are fully customizable. Each vault operates independently with its own policies, allowing you to set quorums and sub-quorums to match your needs. Users can have permissions to initiate vault operations, or to initiate and approve them.
### Wallets
Inside a vault, each asset is stored within a wallet. It is possible to have multiple wallets of the same asset inside a vault. Holding multiple wallets can be beneficial for an organization—for example, to segregate assets according to the receiving counterparty.
### Addresses
Each wallet can have one or more addresses. For account-based networks like Ethereum, the wallet address is unique. For unspent transaction output (UTXO) networks like Bitcoin, you can create as many different addresses as needed, all pooled to the same wallet.
## Managing vaults
Administrators may change vault settings if circumstances change. Changes to policies and users are subject to quorum approval.
### Updating vault details
Tap the vault you want to adjust, then tap the pencil icon next to the vault name.
Edit the vault name and description as necessary and tap **Save**. Updating vault details does not require biometric approval.
Administrators may delete vaults that are no longer in use from the vault details screen. Deletion is submitted for quorum approval.
### Updating vault users
Administrators may update which users are Operators in a vault and adjust each user's privileges between **Initiate only** and **Initiate and approve**.
Tap the vault, then tap the settings icon in the upper right corner.
To extend a user's access, go to **Users** and tap **Add user**. To change an existing user's privileges, select the user and change from **Initiate and approve** to **Initiate only** (or vice versa), then tap **Save changes**.
After making all changes, follow the prompts, tap **Finish and review**, add an optional comment, and complete biometric endorsement to submit for quorum approval.
### Removing a vault user
Tap the vault, tap the settings icon in the upper right corner, then tap **Users**.
Tap **Select**, choose the user or users to remove, then tap **Remove from vault**.
Add a comment (optional), review the operation details, and follow the prompts to submit biometric approval. Removing a user updates the vault's base quorum accordingly.
## Vault policies
All operations in a vault follow the default policy unless you customize policies per operation type. Administrators may edit vault policies to:
* Increase or decrease the number of required approvals
* Add or remove required approvers
* Adjust the sub-quorum (number of approvals required from a selected set of approvers)
### Changing the number of approvers
On the vault settings menu, tap **Vault policies**, then tap the arrow next to the policy you want to edit.
Select **Quorum**, choose the number of quorum approvers, and tap the back arrow.
Tap **Finish and review** and follow the prompts to submit biometric approval. Quorum approval is required.
### Adding or removing required approvers
On the vault settings menu, tap **Vault policies** and select the policy you want to edit.
Select **Edit** next to required approvers. Make the needed changes and tap the back arrow to return to the main menu.
Tap **Finish and review** and follow the prompts to submit biometric approval. Quorum approval is required.
### Changing the sub-quorum
On the vault settings menu, tap **Vault policies** and select the policy you want to edit.
Select **Sub-quorum**, choose the number of sub-quorum approvers, and tap the back arrow to save changes.
Tap **Finish and review** and follow the prompts to submit biometric approval. Quorum approval is required.
### Resetting to the default policy
On the vault settings menu, tap **Vault policies** and select the policy you want to reset.
Select **Edit** next to required approvers, then confirm that you want to reset the policy.
Tap **Finish and review** and follow the prompts to submit biometric approval. Quorum approval is required.
## Wallets
From the wallet details page you can:
* Check wallet balances and holdings
* Generate additional wallet addresses (where applicable)
* Initiate withdrawals
* Check the deposit address and pooled wallet addresses (where applicable)
* Edit the wallet name
### Accessing wallet details
On the vault page, select the asset to view the associated wallets in the vault. Tap the wallet to see its details. Under **Details** you can copy or share your deposit address.
### Adding a new wallet (iOS)
On the vault page, select the asset to view associated wallets.
Tap the wallet icon with the **+** button in the top right corner, then tap **Create new wallet** to acknowledge the disclosure and continue.
You will be prompted to download the encrypted wallet key. Tap **Download wallet key** and choose your preferred save method (for example, **Save to files**). If you already have wallet keys downloaded, select **Keep both** and rename as needed.
New wallet keys can also be exported to your team via email by updating your key download preferences from the web dashboard. If you have previously elected to receive keys by email, you will not be prompted to download at this step.
After saving your wallet key, enter a name for the new wallet.
Tap **Deposit** to display the address and QR code. Copy or share your deposit address.
The encrypted wallet key is NOT sensitive unless decrypted. Only administrators can decrypt the wallet key to import it into another wallet service provider.
# Vaults
Source: https://docs.anchorage.com/knowledge-base/porto/vaults-wallets/vaults
Create and manage vaults to organize your digital assets.
You're viewing **Porto** documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/users/overview)
Vaults are secure containers that hold your digital assets. Each vault can have its own users, permissions, and approval policies, allowing you to organize assets by purpose, department, or risk profile.
## What is a vault
A vault is:
* **An asset container** — Holds one or more wallets for different digital assets
* **A policy boundary** — Each vault has its own governance rules and approval requirements
* **A security perimeter** — Only authorized users can access vaults and initiate operations
* **An audit unit** — All vault activity is logged and traceable
Vaults let you segregate assets and apply different rules to different parts of your organization.
## Vault types
Vaults can be configured for different purposes:
* **Treasury vault** — For storing your main digital asset reserves
* **Trading vault** — For frequent swaps and conversions (if enabled)
* **Settlement vault** — For specific counterparty transactions
* **Custody vault** — For assets held on behalf of clients
Your organization's administrator sets up vault types and policies.
## Create a vault
From the home screen, tap **Vaults**.
Select the **Create new vault** or **+** button.
Provide:
* **Vault name** — A descriptive name (e.g., "Treasury Reserves")
* **Description** — Optional notes about the vault's purpose
* **Select account** — Choose which account this vault belongs to
Select an existing [vault policy](/knowledge-base/porto/policies/customizing-vault-policies) or create a new one. The policy defines approval requirements for operations in this vault.
Specify which team members have access to the vault and their roles (Operator, Initiator, Approver, Admin).
Verify all details, then tap **Submit for approval**.
If you have permissions, complete biometric authentication to authorize vault creation.
Vault creation typically requires admin approval and Anchorage Digital review before the vault becomes active.
## View vault details
From the home screen, tap the vault you want to view.
You'll see all assets and wallets in the vault with current balances.
Tap the vault name or settings icon to see vault details, users, and policies.
## Rename or edit vault details
From the vault screen, tap the **Settings** icon or vault name.
Tap **Edit** next to the vault name or description.
Update the name or description.
Tap **Save**. Changes require approval based on your vault's policies.
Complete biometric authentication to confirm the change.
## Add users to a vault
Tap the vault name, then **Settings**.
Tap **Users** or **Team**.
Tap **Add user** and select a team member from your organization.
Assign a role: Operator, Initiator, Approver, or Admin (see role definitions below).
Tap **Submit**. Adding users requires approval based on your policies.
Complete biometric authentication to authorize the addition.
## Vault roles
| Role | Permissions |
| :------------ | :----------------------------------------------------------- |
| **Viewer** | View vault assets and activity (read-only) |
| **Operator** | View assets, initiate deposits and receive requests |
| **Initiator** | Operator + initiate transfers and withdrawals |
| **Approver** | Approve operations initiated by others |
| **Admin** | Full access—manage users, policies, settings, and operations |
## Vault policies
Policies define approval requirements for operations in a vault:
* **Admin policy** — Rules that apply to user management and settings changes
* **Vault policy** — Rules that apply to asset transfers and operations
* **Quorum requirements** — Who must approve and how many signatures are needed
Administrators set vault policies. See [vault policies](/knowledge-base/porto/policies/customizing-vault-policies) for details on customizing rules.
## Remove a user from a vault
Tap the vault name, then **Settings > Users**.
Tap the user you want to remove.
Select **Remove user**.
Confirm the removal. This requires approval based on your policies.
Complete biometric authentication to confirm removal.
Removing a user doesn't delete their historical activity. All past transactions and approvals remain in the audit trail.
## Archive or delete a vault
Vaults can only be archived or deleted by administrators. Contact your organization's admin team if you need to deprecate a vault.
Archived vaults:
* Cannot accept new operations
* Remain in your history for audit purposes
* Can be accessed for viewing past activity
# Wallet recovery
Source: https://docs.anchorage.com/knowledge-base/porto/vaults-wallets/wallet-recovery
Recover access to your wallets if you lose your device or need to restore your account.
You're viewing **Porto** documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/users/overview)
If you lose access to your Porto account, device, or need to restore your wallets, you have several recovery options available. The recovery method depends on what you've lost access to and your organization's security configuration.
## Before you start
Wallet recovery requires secure verification of your identity. Depending on your situation:
* **Lost your phone but remember your password** — Use the standard login and device recovery flow
* **Lost your phone and password** — Contact your organization's administrator for account recovery
* **Switching devices** — Sign in on your new device and set up biometric authentication
* **Organization account recovery** — Use the organization recovery document if your organization has set one up
## Recover your account
Open the Porto app on any device (your new phone, a tablet, or a computer).
Use your email and password to sign in to your Porto account.
Complete the identity verification flow — this may include:
* Biometric authentication (Face ID or Touch ID) if enabled
* A code sent to your email address
* Security questions or recovery codes
Once logged in, set up Face ID or Touch ID on your new device to approve future transactions.
Your wallets and vaults will automatically appear once you're signed in and verified.
Your wallet data is backed up securely with Porto and can be restored to any authorized device. You don't need to recreate your wallets or vaults.
## Forgot your password
If you forget your Porto password:
On the login screen, select **Forgot password** or **Can't sign in**.
Provide the email address associated with your Porto account.
Porto will send you a password reset link. Check your email (and spam folder) for the message.
Open the email and click the password reset link.
Set a strong new password for your account.
Go back to the Porto app and sign in with your email and new password.
## Organization recovery document
If your organization has set up an organization recovery document, you can use it to recover access to your account and vaults in certain scenarios. Your administrator will provide you with this document.
See [Organization recovery document](/knowledge-base/porto/security/org-recovery-document) for details on how to use it.
## Biometric authentication recovery
If you're signed in to Porto but your biometric authentication isn't working:
1. **Try again** — Sometimes biometric authentication fails temporarily due to sensor issues. Try a few more times.
2. **Use your password** — If biometric authentication is disabled, you can always sign in with your email and password.
3. **Re-enable biometric authentication** — Go to **Settings** > **Security** and set up Face ID or Touch ID again on your current device.
## Multi-device recovery
If you're registered on multiple devices and lose one:
1. **Sign in on your remaining device** — You can continue using Porto normally
2. **Remove the lost device** — Go to **Settings** > **Devices** and remove the lost device from your account
3. **Set up biometric authentication** — Ensure your remaining device has biometric authentication configured
## If you lose access completely
If you lose all access to your accounts and devices:
1. **Contact your organization's administrator** — They may be able to help recover your account or reset your access
2. **Use the organization recovery document** — If available, this document can help restore access
3. **Provide identity verification** — You may be asked to verify your identity through additional means (email verification, security questions, official ID verification)
## Best practices for avoiding recovery issues
* **Write down your password** — Store it securely in a password manager (like 1Password, Bitwarden, or Dashlane)
* **Back up recovery codes** — If your organization provides recovery codes, store them in a secure location separate from your device
* **Keep your email secure** — Password resets are sent to your email, so protect your email account with a strong password and 2FA
* **Save the organization recovery document** — If provided, keep it in a safe place (printed or securely stored digital copy)
* **Enable biometric authentication** — It's the fastest way to access your account and recovery on a new device
# Wallets
Source: https://docs.anchorage.com/knowledge-base/porto/vaults-wallets/wallets
Understand how wallets work within vaults and manage multiple asset addresses.
You're viewing **Porto** documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/users/overview)
A wallet is a container for a single asset type (like Bitcoin or Ethereum) within a vault. Each vault can hold multiple wallets for different assets, allowing you to organize and manage diverse digital assets in one place.
## What is a wallet
* **An asset container** — Holds cryptocurrency of a specific type (Bitcoin, Ethereum, etc.)
* **Linked to a vault** — Every wallet belongs to exactly one vault and inherits the vault's policies and permissions
* **Multiple addresses** — A wallet can have multiple receive addresses for the same asset
* **Unique balance** — Each wallet tracks its own balance independently
When you create a vault, you can add wallets for the assets you plan to hold. You can also add new wallets to an existing vault at any time.
## View your wallets
From the home screen, select the vault where your wallets are stored.
You'll see a list of all wallets in this vault with their current balances.
Select any wallet to see its details, including addresses, recent transactions, and actions you can take.
## Add a wallet to a vault
From the home screen, tap the vault you want to add a wallet to.
Select the **Add wallet** or **+** button, or look for an "Add asset" option.
Select the asset you want to add (Bitcoin, Ethereum, Solana, etc.) from the list of supported assets.
Optionally name the wallet or add notes about its purpose.
Tap **Submit** or **Add wallet**. Depending on your vault's policies, this may require approval.
If you have approver permissions, complete biometric authentication to confirm adding the wallet.
Adding a wallet does not require moving or depositing assets — it simply activates that asset type in the vault. You can deposit to that wallet anytime.
## Receive addresses
Each wallet can have multiple receive addresses, allowing different parties to send you assets to different addresses. Addresses can be public or private, depending on your organization's privacy preferences.
From the vault, tap the asset wallet you want to generate an address for.
Select **Receive**, **Add address**, or **Generate address**.
Some organizations allow you to choose whether the address is public or private. Select your preference.
The app will generate a new address for receiving assets to this wallet.
Copy the address to share with senders, or let them scan the QR code displayed.
## Wallet status
Wallets show different statuses based on their state:
* **Active** — The wallet is set up and ready to receive and send assets
* **Pending** — The wallet is waiting for approval before it can be used
* **Inactive** — The wallet has been disabled and cannot send or receive assets
For details on managing wallet status, see [Key management](/knowledge-base/porto/security/key-management).
## Wallet recovery
If you lose access to your device or need to restore your wallets, see [Wallet recovery](/knowledge-base/porto/vaults-wallets/wallet-recovery) for recovery options and procedures.
# Web dashboard
Source: https://docs.anchorage.com/knowledge-base/porto/vaults-wallets/web-dashboard
Manage vaults, wallets, trusted destinations, and account settings.
You're viewing **Porto** documentation — a distinct product from Anchorage Digital's core custody platform. [Go to Anchorage Digital docs →](/knowledge-base/platform/users/overview)
## Log in
Visit [https://www.porto.xyz](https://www.porto.xyz) and select **Login** at the top right, or go directly to the login page.
Go to [https://www.porto.xyz](https://www.porto.xyz) and select **Login**.
Open the Porto iOS app and navigate to **Settings**.
Tap **Web dashboard login**, then scan the QR code displayed on the website.
Review the location of the device trying to log in and allow access to complete login.
## Homepage
Once logged in, the homepage provides a master view of your account. Click **Portfolio** to view the breakdown of holdings by asset.
## Vaults, wallets & addresses
### Vaults
Click **Vaults** to get an overview of all vaults in your account. From the vault page, you can view the vault's portfolio and details, including wallets and addresses.
### Create a deposit address
On the vault page, click **Deposit** to create a new deposit address.
Search from the list of assets you would like to deposit and select the asset.
Before sharing the deposit address, click **Download encrypted key** and store it safely offline.
Copy and share the deposit address with the counterparty.
Deposit addresses can also be created in the iOS app.
### Addresses
Under **Addresses**, all addresses associated with the vault are listed. You can search by asset, address, or wallet. Click on a wallet name to see the details of the associated wallet.
### Create a new wallet
Select the button at the bottom right to create a new wallet (for example, **Create new Bitcoin wallet**).
Before confirming your new wallet, click **Download encrypted key** and store it safely offline.
Review the information and click **Create new wallet** to confirm. The new wallet will appear in the vault.
### Create a new address for a given wallet
Click the generate icon to create a new wallet address.
Additional or pooled wallet addresses are only available on UTXO-based networks. You must click **Download encrypted key** and store it safely offline for each new address created.
### Withdraw assets
From the vault details page, click **Withdraw**.
Select the asset, the wallet to withdraw from, the amount, and the destination type. If you select a trusted destination, choose the appropriate address. Click **Continue**.
Add a comment (optional) and click **Preview withdrawal**. Review the operation details and click **Preview withdrawal** to submit biometric approval.
Complete the endorsement process from your Porto iOS app. Once quorum is met, the withdrawal operation is complete.
## Key download preferences
To update your download preferences for encrypted wallet keys:
In the web dashboard, navigate to **Settings** and click **Encrypted wallet keys**.
Click on the **Download preferences** tab.
Select your preferred method for downloading your organization's encrypted wallet keys.
## Operations
Navigate to **Operations** to view, filter, and download pending and past account activity. Export transaction data for bookkeeping, performance tracking, and analysis.
## Web3 access
In the web dashboard, select **Web3** in the dock to view or disconnect active connections to dApps.
## Adding trusted smart contracts
You can add multiple trusted smart contracts at once by uploading a file containing all required information.
### Upload trusted smart contracts via CSV
Download the Excel spreadsheet template.
Open the template in your preferred spreadsheet editor (Excel or Google Sheets) and fill it out. When finished, download or export the file as a CSV.
If using Google Sheets, go to **File > Download > Comma Separated Values (.csv)**.
In the web dashboard, in **Settings**, under **Trusted addresses**, select **Trusted smart contracts**. Select **Add** and **Upload multiple from file**, then upload your completed CSV file.
Porto will parse the file and allow you to review the submitted information. Correct any errors if prompted. Click **Submit** to begin adding the trusted smart contracts. You will be prompted to approve the addition on your iOS device—quorum approval is required.
After the operation is approved and reviewed, your new trusted smart contracts will be added to your account and you will receive a notification confirming completion.
### Trusted smart contracts template fields
| Field | Required | Description |
| ------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `name` | Yes | The name of the trusted smart contract as it appears in the web dashboard or iOS app. Must be between 3 and 32 characters. |
| `networkName` | Yes | The blockchain network name. Currently only Ethereum is supported. |
| `address` | Yes | The smart contract address (e.g., `0x...`) for the provided blockchain network. |
| `vaultID(s)` | Yes | The unique ID(s) of the vault(s) to associate with this smart contract. Vault IDs are found under the vault name. To add multiple vaults, separate each ID with a comma (e.g., `1234abcd,5678efgh`). |
| `description` | No | A short description of the trusted smart contract. Maximum 200 characters. |
## Adding trusted destinations
You can add multiple trusted destinations at once by uploading a file containing all required information.
Contact [portohelp@anchorage.com](mailto:portohelp@anchorage.com) if you have questions about adding trusted destinations.
### Upload trusted destinations via CSV
Download the provided Excel spreadsheet template.
Open the template in your preferred spreadsheet editor (Excel or Google Sheets) and fill it out. When finished, download or export the file as a CSV.
If using Google Sheets, go to **File > Download > Comma Separated Values (.csv)**.
In the web dashboard, in **Settings**, under **Trusted addresses**, select **Trusted destinations**. Select **Add**, then **Upload multiple from file**, and upload your completed CSV file.
Review the list of trusted destinations, make any necessary adjustments, and submit for approval when ready.
Complete the endorsement process from your Porto app. Once quorum is met, the Porto team will review the operation for approval.
### Trusted destinations template fields
The fields in the template correspond to the fields you complete when adding a trusted destination in the web dashboard or iOS app.
| Field | Required | Description |
| ------ | -------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| `name` | Yes | The name of the trusted destination as it appears in the web dashboard or iOS app when choosing destination addresses for withdrawals. |
### Remove trusted destinations
Only administrators with trusted destination management permissions can remove trusted destinations. Removal requires quorum and Porto approval.
In the web dashboard, in **Settings**, under **Trusted addresses**, select **Trusted destinations**.
Click the three dots next to the trusted destination you want to remove, then click **Remove**.
Biometric approval in the iOS app is required. Once quorum is met, the Porto team will review the operation.