Upsert Custody Provider
Creates or updates a custody provider's configuration. Saving never changes which provider is active: a new provider is created inactive, and an existing one keeps its is_active. Use Activate Custody Provider to switch.
Credentials are nullable on purpose. You cannot read username, password or api_key back, so a save that leaves them out must not erase them:
- omitted or
nullkeeps the stored value; ""clears it;- any other string replaces it.
webhook.auth_type and webhook.username work the same way (omitted or null keeps). The webhook secret is not writable here: it is generated by Regenerate Webhook Secret and stored only as a hash. host, port and timeout are always written as sent.
Rules a save is checked against:
- Stored secrets stay with their endpoint. Moving the provider to another
hostorportwhile a storedpassword,api_keyor client certificate would be carried over is refused with10015, naming each field to send again (password,api_key,client_key). A client certificate cannot be sent through this API, so a provider that has one cannot be moved to another endpoint here. - Plain http only inside the cluster. This API cannot turn TLS on; a provider keeps the TLS setting it already has, and a new one starts with TLS off. With TLS off,
hostmust be an in-cluster host listed for the environment, otherwise the save is refused with10015naminghost. - A basic webhook pair is kept whole. With
webhook.auth_typebasicand a secret already generated,webhook.usernamecannot be cleared (or left empty when switching tobasic).
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
PUT /v2/admin/custodial-wallets/{provider}
Parameters
| Name | Type | In | Description |
|---|---|---|---|
provider | string | path | Required. Provider key: rudiq or taurus |
Headers
| Name | Description |
|---|---|
Authorization | Required. Bearer <access_token> |
Content-Type | Required. application/json |
Body
| Field | Type | Required | Description |
|---|---|---|---|
host | string | Yes | Host name of the provider's API, without scheme, port or path |
port | integer | No | Port of the provider's API, 0 or greater |
timeout | integer | No | Request timeout in seconds, 0 or greater |
username | string | null | No | Username the platform presents to custody. null keeps, "" clears |
password | string | null | No | Password the platform presents to custody. null keeps, "" clears |
api_key | string | null | No | API key the platform presents to custody. null keeps, "" clears |
webhook | object | null | No | Inbound webhook settings. Omitted or null keeps both |
webhook.auth_type | string | null | No | basic or token. null keeps the stored value (basic for a new provider) |
webhook.username | string | null | No | Username custody sends with basic auth. null keeps |
Example
curl --request PUT \
--url '{{baseUrl}}/v2/admin/custodial-wallets/rudiq' \
--header 'Authorization: Bearer <access_token>' \
--header 'Content-Type: application/json' \
--data '{
"host": "custody-gateway.custody.svc.cluster.local",
"port": 8080,
"timeout": 30,
"username": null,
"password": null,
"api_key": "<custody_api_key>",
"webhook": {
"auth_type": "basic",
"username": "apex-custody"
}
}'
Response
200 OK with the saved provider, masked as on List Custody Providers.
{
"provider": "rudiq",
"host": "custody-gateway.custody.svc.cluster.local",
"port": 8080,
"timeout": 30,
"is_active": false,
"effective_active": false,
"username_set": false,
"password_set": false,
"api_key_set": true,
"api_key_last4": "7c1e",
"configured": true,
"webhook": {
"auth_type": "basic",
"path": "/v2/webhooks/custodial",
"url": "https://integration.example.com/v2/webhooks/custodial",
"username": "apex-custody",
"secret_set": false
},
"created_at": "2026-11-09T11:02:37.640Z",
"updated_at": "2026-11-09T11:02:37.640Z"
}
Errors
| Status | Code | Description |
|---|---|---|
| 400 | 10015 | Validation failed (host missing, negative port or timeout), unsupported provider key, unsupported webhook.auth_type, a basic webhook secret left without its username, or (with details) a stored secret that would move to a new endpoint or a plain-http host outside the cluster |
| 403 | 10005 | The caller is not the platform owner (domain 2) |
See Errors for the error format and common codes.