What a wallet is for
Two things, and they pull in different directions.Receiving — the address
address on its network. That is an
ordinary on-chain transfer; nothing about it is Endl-specific.Settling — the destination
ONRAMP account converts a fiat deposit and settles the
stablecoin into a wallet. That is why walletId is required when you open one —
the wallet supplies the settlement asset, chain and address.Who may create one
The customer must have completed KYC. Create and create-on-network are both gated on it; everything else — list, get, balance, update, delete — is not. An incomplete customer gets403 ERRWLT_1005, and the check is the same completion rule the rest of
the platform uses, so a customer who can transact can create a wallet.
Networks
Fifteen networks are supported platform-wide: EVM mainnets, their testnets, TRON and XRP.Base wallet
that works in production is refused there. The error message lists the networks the
environment you are calling actually allows — read it rather than assuming the full
set.Creating a wallet
Create the customer and get them verified
cus_…
reference id — that is the {userId} in every wallets path — and see them
through KYC.POST the network
network is the only required field. name is optional but must be a non-empty
string if you send it at all, and tags must be an array of strings if present.userId in the body is stripped and ignored — the customer is the one in
the path, and only the one in the path.Read the id and address off the response
walletId (a wlt_… reference), its
address, its network and a status. The address is live from that moment;
there is no activation step.Add further networks, if you need them
wlt_ id and its own address — the
networks are related cryptographically, not merged into one object.What comes back
signingKey block
because you saw one in a custody provider’s own docs, it is removed on purpose and
will not be added.The primary wallet
One wallet per customer can be flaggedisPrimary. The rule is narrow and worth
knowing exactly:
- It is set only on customers created through the partner API.
- It is set only on the first wallet, when the customer has no active primary wallet yet.
- It is only ever granted, never revoked. Creating a second wallet does not move the flag, and re-syncing an existing wallet does not clear it.
Reading balances
Get wallet balance returns the wallet’s native asset, its tokens and a USD total. For most networks the call aggregates across chains in one request. TRON is the exception: TRON balances are queried on their own chain because they are not covered by the aggregate. You do not have to do anything about this — Endl picks the right query from the wallet’s network — but it does mean a TRON wallet’s balance reflects TRON only, while an EVM wallet’s can span the networks its key covers.walletId, and that value is rewritten to
your wlt_… reference before it reaches you. Everything else in the body —
address, chain, native, tokens, totalUsd — is on-chain data and passes through
untouched.Updating and deleting
Update takesname, externalId, or both.
Sending neither is a 400 — a no-op update is treated as a mistake rather than
quietly accepted. Only name is mirrored into Endl’s own record; externalId lives
at the custody layer.
Delete is soft, and it is one-way through this API.
Scoping and reference ids
Every wallets path is/{userId}/…, and the customer is resolved from that path
segment alone. A wallet that belongs to a different customer is reported as
404 ERRWLT_1000 — never 403 — so a partner can never probe which wallet ids
exist under another customer.
Error handling
Wallet-specific failures carry anERRWLT_ code. Everything cross-cutting —
validation, auth, rate limiting — uses the shared ERRCORE_ codes described in
Errors and the response envelope.
Webhooks
Wallets produce two events. Delivery, signing, replay protection and the envelope shape are covered in the Webhooks guide — this is only what is specific to wallets.data.id is the wallet’s wlt_… reference. The payload body is deliberately thin —
network and currency, nothing else.
There is also no wallet.updated. Renaming a wallet emits nothing, and so does
money arriving: an incoming on-chain transfer is a deposit event, not a wallet event.
Common pitfalls
Create wallet returns 400 'network must be one of…' but my network is in the list
Create wallet returns 400 'network must be one of…' but my network is in the list
network exactly: Base, not base.
Everything else in the API is case-insensitive about network names, which is what
makes this one easy to miss.The same create call works in production and fails in sandbox
The same create call works in production and fails in sandbox
BaseSepolia rather than Base.Create wallet returns 403 and the key definitely has the wallets permission
Create wallet returns 403 and the key definitely has the wallets permission
ERRWLT_1005 is the KYC gate, not a permission failure. The customer has not
completed verification. A permission failure is ERRCORE_1005.Every wallet says currency USDC, including ones holding USDT
Every wallet says currency USDC, including ones holding USDT
currency is a local default stamped at creation, not a reading of the chain and
not a restriction on the wallet. Use Get wallet balance for holdings.I called create-on-network and my original wallet is unchanged
I called create-on-network and my original wallet is unchanged
wlt_ id and
address. The wallet you named in the path is untouched.Get wallet returns 404 for a wallet that is definitely there
Get wallet returns 404 for a wallet that is definitely there
wlt_ reference is well-formed but
unknown. Check List wallets for that customer.Delete returned 200 and I was expecting 204
Delete returned 200 and I was expecting 204
200 with status: "deleted". Nothing in the v0 surface
returns an empty 204.I deleted a wallet that still had a balance
I deleted a wallet that still had a balance
I want one wallet that receives on every chain
I want one wallet that receives on every chain
Glossary
Api-Version: 2026-09.1. The network list is platform-wide; what a
given environment and a given customer can actually use is narrower, so read errors
rather than hardcoding this page.