Test Custody Connection
Runs one live probe against a custody configuration without saving it. Use it before saving or activating a provider.
Which probe runs. method in the response says which:
connection_test— providers with a dedicated authenticated test endpoint (rudiq). It checks the whole authentication chain and returns the API key's scope and expiry indetail, without touching any wallet.network_idis not needed.native_balance— the fallback for a provider without such an endpoint: a native-balance read of the zero address on the networknetwork_idnames.network_idis then required.
taurus has no client yet, so testing it answers ok: false.
Testing the stored row. With use_stored: true the saved configuration is probed, and every submitted field that is not empty (host, port, timeout, api_key) overrides it, so an edit can be tested without retyping secrets. The stored TLS setting and client certificate are used as well. A stored API key or client certificate is only presented at the stored host and port: naming another endpoint while relying on one is refused with 10002 (domain 83). Send the API key to test another host. Without use_stored, the probe goes over plain http.
Allowed targets. The endpoint must be public https, or an in-cluster host the environment lists (custody is normally reached over plain http inside the cluster). Anything else is refused with 10001 (domain 83) before anything is sent.
A probe that fails is still a 200, with ok: false and the reason in error. A 4xx means the request itself was refused.
Platform owner only. The caller's node must be the platform root node; any other caller is refused with 403 / 10005.
Required permission: custodial-wallet:update
Request
POST /v2/admin/custodial-wallets/test
Headers
| Name | Description |
|---|---|
Authorization | Required. Bearer <access_token> |
Content-Type | Required. application/json |
Body
| Field | Type | Required | Description |
|---|---|---|---|
provider | string | Yes | Provider key: rudiq or taurus |
host | string | No | Host name to probe. With use_stored, empty means the stored host |
port | integer | No | Port to probe, 0 or greater. With use_stored, 0 means the stored port |
api_key | string | No | API key to probe with. With use_stored, empty means the stored key |
timeout | integer | No | Request timeout in seconds, 0 or greater. With use_stored, 0 means the stored timeout |
use_stored | boolean | No | Probe the saved configuration, overridden by the non-empty fields above |
network_id | integer | Conditional | Numeric chain network id (e.g. 11155111) for the native_balance probe. Required only for that probe; the network must be known to the platform |
username | string | No | Accepted but not used by the probe |
password | string | No | Accepted but not used by the probe |
Example
curl --request POST \
--url '{{baseUrl}}/v2/admin/custodial-wallets/test' \
--header 'Authorization: Bearer <access_token>' \
--header 'Content-Type: application/json' \
--data '{
"provider": "rudiq",
"use_stored": true
}'
Response
{
"ok": true,
"latency_ms": 87,
"method": "connection_test",
"detail": {
"status": "ok",
"api_key_id": "3f1d2b6e-0000-4000-8000-000000000001",
"api_key_name": "apex-platform",
"node_id": "3f1d2b6e-0000-4000-8000-000000000002",
"node_name": "root",
"permissions": ["read", "transfer:create"],
"expires_at": null,
"client_certificate_required": false,
"server_time": "2026-11-09T11:08:14Z"
}
}
Response Fields
| Field | Type | Description |
|---|---|---|
ok | boolean | Whether the probe succeeded |
latency_ms | integer | Duration of the probe in milliseconds |
method | string | connection_test or native_balance. Empty when the client could not be built (for example taurus, or rudiq without an API key) |
network_id | integer | native_balance only: the network that was read |
symbol | string | native_balance only, on success: the native currency symbol custody reported |
detail | object | connection_test only, on success: what custody reports about the key |
detail.status | string | Status custody reports |
detail.api_key_id | string | Id of the API key at custody |
detail.api_key_name | string | Name of the API key at custody |
detail.node_id | string | Custody's id of the node the key belongs to |
detail.node_name | string | Custody's name of that node |
detail.permissions | array | Scopes granted to the key |
detail.expires_at | string | null | When the key expires (ISO 8601); null if it does not |
detail.client_certificate_required | boolean | Whether custody requires a client certificate from the platform |
detail.server_time | string | null | Custody's clock (ISO 8601) |
error | string | Only when ok is false: why the probe failed |
Errors
| Status | Code | Description |
|---|---|---|
| 400 | 10015 | Validation failed (provider missing, a negative number) — see details. Also: unsupported provider key, use_stored with no saved configuration, network_id missing or unknown for a native_balance probe |
| 400 | 10001 | Target refused: not https outside the cluster, does not resolve, or resolves to a private or metadata address (domain 83) |
| 400 | 10002 | A stored API key or client certificate would be presented to another host or port (domain 83) |
| 403 | 10005 | The caller is not the platform owner (domain 2) |
See Errors for the error format and common codes.