The networks a workspace starts with
Every workspace’s registry is seeded from the same ten built-in networks:
| Slug | Network | VM | Chain ID |
|---|---|---|---|
ethereum |
Ethereum | evm |
1 |
base |
Base | evm |
8453 |
bnbchain |
BNB Chain | evm |
56 |
arbitrum |
Arbitrum | evm |
42161 |
optimism |
OP Mainnet | evm |
10 |
sepolia |
Sepolia | evm |
11155111 |
arbitrum-sepolia |
Arbitrum Sepolia | evm |
421614 |
solana |
Solana | svm |
101 |
solana-testnet |
Solana Testnet | svm |
102 |
solana-devnet |
Solana Devnet | svm |
103 |
These slugs are what every network selector and defaultNetwork accepts. A
well-formed slug that is not one of them — or one your operator removed — is a
404, not a 400.
Use a testnet while you are integrating. sepolia and solana-devnet
carry no real value, and every example in these docs uses ethereum only
because it is the obvious name. A first transaction on ethereum is a real
mainnet transaction.
TEE Docker ships no RPC service. Anything that touches a chain — building, simulating, submitting, or checking a transaction — runs against an endpoint you or your operator supplied.
Resolution
An endpoint can come from three places. They are not searched in turn at request time — the workspace’s own network registry is read once, and each entry already carries the provenance it was given:
The workspace registry — authoritative
What a route actually reads. PUT /v1/workspace/networks/{slug} writes
straight into it, and is how an endpoint changes once a workspace exists.
The tenant rpc map — a seed, not a lookup
Your operator’s map is copied into the registry when the workspace is created, over the built-in defaults. That is the only moment it is read.
A wative-core built-in — permitted, not searched
Networks your operator never configured keep the URL wative-core ships. That
entry is usable only where allowDefaultRpc permits it, and permission is
checked on every call, not once at creation.
So a registry entry is necessary but not sufficient. A call fails with 409
and rpc_not_configured in two cases: the network has no URL at all, or it has
a built-in one and allowDefaultRpc is off.
Provenance is about how an endpoint was set, not what it points at. An explicit
PUT or an operator seed counts as tenant even when its URL happens to equal
the one wative-core ships.
Every answer says where its endpoint came from
Resolution is never ambiguous. The reported source is one of three values:
rpcSource |
Meaning |
|---|---|
tenant |
A workspace-registered or tenant-configured endpoint answered |
builtin |
wative-core’s shipped default answered — an endpoint nobody here chose |
none |
Nothing usable is configured for this network |
GET /v1/workspace/networks reports it per network, and is the only place
none appears — it is a description of configuration, not of a call.
The four transaction routes stamp the source on the response as the
x-rpc-source header, so “why is this slow” or “which endpoint actually
served this” is answerable from the response alone. The header only ever reads
tenant or builtin: a network that would resolve to none fails with 409
before a response exists to stamp.
When a route needs an endpoint and resolution returns none, the call fails
with 409 and code rpc_not_configured.
Setting an endpoint
curl -X PUT "$API_URL/workspace/networks/ethereum" \
-H "Authorization: Bearer $TOKEN" \
-H "content-type: application/json" \
-d '{"rpcUrl":"https://your-endpoint.example.com/eth"}'The URL is admitted through a boundary check before it is stored — an endpoint
the service refuses to accept returns 400 with rpc_endpoint_rejected.
What the boundary accepts
Every rule below produces that same 400, so it is worth knowing them before
you debug one:
| Rule | Rejected |
|---|---|
Scheme must be https: |
Any http:// endpoint |
| No credentials in the authority | https://user:pass@host/… — put an API key in the path or query instead, which is allowed |
| No fragment | https://host/rpc#x |
| Host must resolve to a globally routable address | localhost, 127.0.0.1, 10.x, 172.16–31.x, 192.168.x, 169.254.x, CGNAT, and the IPv6 equivalents |
| Host must resolve at all | A name with no A or AAAA record |
| At most 2048 bytes | A longer URL |
There is no port restriction — a non-standard port is fine.
The name is resolved when you register it and on every request that uses it, and the resolved address is pinned for the connection. So an endpoint that starts resolving to a private address later begins failing, even though it was accepted at registration. The update is applied transactionally: if the new endpoint cannot be resolved after being written, the previous one is restored rather than leaving the workspace pointing at something unusable.
Requires the write scope. Reading the list requires read.
Failures you should expect
Chain-touching routes surface transport problems distinctly from on-chain outcomes:
| Code | Status | Meaning |
|---|---|---|
rpc_not_configured |
409 | No usable endpoint for that network |
rpc_unreachable |
502 | The endpoint did not respond, or answered non-2xx |
rpc_rejected |
502 | The endpoint responded with a refusal |
rpc_endpoint_rejected |
400 | The URL you supplied was refused at admission |
rpc_capacity_exceeded |
429 | Too many concurrent chain operations |
unsupported_network |
400 | The signing engine cannot work with that network |
account_not_found |
404 | The ?network= selector named a network this workspace does not define |
A simulation that fails on-chain is a 200 with success: false and a revert
reason. A simulation that could not complete at all is a transport error, and is
never rendered as 200.
Related
- Networks endpoints — request and response shapes
- Send transactions — where RPC actually matters
- Errors — the full catalog