# Managing Key Shares and Deriving Public Keys

Every Key Share generated by or imported into the Vertex is stored under a unique `key_id`, and optionally a human-readable `key_name`.
This page covers the lifecycle operations on stored Key Shares: listing them, deleting them, and deriving public keys (and therefore addresses) from them.

The endpoints below exist for each supported signature algorithm under its own path prefix: `/ecdsa`, `/ed25519`, `/exportable-ed25519`, `/bip340` and `/sr25519`.
Each example uses one algorithm; replace the prefix to target another algorithm, and see the [API Reference](https://docs.sodot.dev/vertex-api-reference/) for the exact request and response shape of every variant.

## Listing Key Shares

:::note[Required Role]
This endpoint requires a User with the `KeysManager` Role.
:::

To list all Key Shares associated with the authenticated User, call the [`list-key-shares`](https://docs.sodot.dev/vertex-api-reference/#tag/ecdsa/GET/ecdsa/list-key-shares) endpoint:

```bash
curl -L -X GET 'https://<YOUR_VERTEX>/ecdsa/list-key-shares' \
-H 'Accept: application/json' \
-H 'Authorization: <USER_API_KEY>'
```

The response contains one entry per Key Share, including its type, optional name and the [Key Permissions](/vertex/users_and_access_control#key-ownership-and-permissions) assigned to Users and Groups:

```json
{
  "key_shares": [
    {
      "key_id": "<KEY_ID>",
      "key_type": "Ecdsa",
      "name": "my-treasury-key",
      "key_users": [
        {
          "user_id": "<USER_ID>",
          "user_name": "prod-signer",
          "usage_permission": "Admin"
        }
      ],
      "key_groups": []
    }
  ]
}
```

:::tip
`list-key-shares` only returns the shares of the calling User. A `SystemAdmin` or `ResourceViewer` can list the Keys of any User using the [`/admin/list-all-user-keys`](https://docs.sodot.dev/vertex-api-reference/#tag/admin/GET/admin/list-all-user-keys) endpoint.
:::

## Deleting a Key Share

:::note[Required Role]
This endpoint requires a User with the `KeysManager` Role, holding the `Admin` [Key Permission](/vertex/users_and_access_control#key-ownership-and-permissions) for the Key being deleted.
:::

To delete a Key Share, send a `DELETE` request to the [`delete-key-share`](https://docs.sodot.dev/vertex-api-reference/#tag/ecdsa/DELETE/ecdsa/delete-key-share) endpoint.
The Key is identified by either a `key_id` or a `key_name` query parameter. Provide exactly one of the two, not both:

```bash
curl -L -X DELETE 'https://<YOUR_VERTEX>/ecdsa/delete-key-share?key_id=<KEY_ID>' \
-H 'Accept: application/json' \
-H 'Authorization: <USER_API_KEY>'
```

A `200 OK` response indicates the Key Share was deleted.

:::warning[Deletion is Irreversible]
Once a Key Share is deleted it cannot be recovered. If the share may be needed again (for example, it protects funds), [export a backup](/vertex/backup_key_shares) before deleting it.
:::

Deleting all of a User's Key Shares is also a prerequisite for [deleting the User](/vertex/users_and_access_control#deleting-a-user) itself.

:::note
An older variant of this endpoint takes the `key_id` as a path parameter (`DELETE /ecdsa/delete-key-share/{key_id}`). It is deprecated; use the query parameter form above.
:::

## Deriving Public Keys

Each Key Share is the root of a [BIP-32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki) tree: a single `t-of-n` key can serve many public keys (and therefore many addresses), one per non-hardened derivation path.
The `derive-pubkey` family of endpoints returns the public key for a given path, so you can generate addresses without performing any MPC operation.

Use the same `derivation_path` later when [signing](/vertex/signing) to produce a signature that verifies under the derived public key.

:::note[Required Role]
These endpoints require a User with the `CryptoUser` or `KeysManager` Role.
The `Use` [Key Permission](/vertex/users_and_access_control#key-ownership-and-permissions) is sufficient, so Key Users can derive public keys for the Keys they are allowed to sign with.
:::

All request bodies identify the Key by either `key_id` or `key_name` (exactly one of the two). The response format differs per algorithm, as shown below.

### Ecdsa

Call the [`/ecdsa/derive-pubkey`](https://docs.sodot.dev/vertex-api-reference/#tag/ecdsa/POST/ecdsa/derive-pubkey) endpoint:

```bash
curl -L -X POST 'https://<YOUR_VERTEX>/ecdsa/derive-pubkey' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H 'Authorization: <USER_API_KEY>' \
--data-raw '{
  "key_id": "<KEY_ID>",
  "derivation_path": [44, 60, 0, 0, 0]
}'
```

The response contains the derived public key in both SEC1 encodings (hex), as well as the xPub of the derived key (base58):

```json
{
  "compressed": "02c901eb...",
  "uncompressed": "04c901eb...",
  "xpub": "xpub6FnCn..."
}
```

### Ed25519

Call the [`/ed25519/derive-pubkey`](https://docs.sodot.dev/vertex-api-reference/#tag/ed25519/POST/ed25519/derive-pubkey) endpoint with the same request body as Ecdsa.
The response contains the derived public key (hex) and an sPub (base58), which is Sodot's Ed25519 equivalent of an xPub:

```json
{
  "pubkey": "4dc32369...",
  "spub": "spub1abc..."
}
```

### Sr25519

Call the [`/sr25519/derive-pubkey`](https://docs.sodot.dev/vertex-api-reference/#tag/sr25519/POST/sr25519/derive-pubkey) endpoint.
Sr25519 uses soft (non-hardened) Substrate-style derivation, so the request differs from the other algorithms: the Key is identified by a nested `key_ident` object, and `derivation_path` is an array of strings (path junctions):

```bash
curl -L -X POST 'https://<YOUR_VERTEX>/sr25519/derive-pubkey' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H 'Authorization: <USER_API_KEY>' \
--data-raw '{
  "key_ident": { "key_id": "<KEY_ID>" },
  "derivation_path": ["polkadot", "0"]
}'
```

The response contains only the derived public key (hex):

```json
{
  "pubkey": "c901eb1b..."
}
```

### BIP340 (Taproot)

Call the [`/bip340/derive-tweak-pubkey`](https://docs.sodot.dev/vertex-api-reference/#tag/bip340/POST/bip340/derive-tweak-pubkey) endpoint.
In addition to the derivation path, it accepts an optional 32-byte `tweak`, allowing you to derive [Taproot tweaked public keys](https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki) as used for P2TR outputs:

```bash
curl -L -X POST 'https://<YOUR_VERTEX>/bip340/derive-tweak-pubkey' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H 'Authorization: <USER_API_KEY>' \
--data-raw '{
  "key_id": "<KEY_ID>",
  "derivation_path": [86, 0, 0, 0, 0],
  "tweak": "<OPTIONAL_32_BYTE_TWEAK>"
}'
```

The response contains the x-only public key (hex). When no `tweak` is provided, it also contains the xPub of the derived key; when a `tweak` is provided, `xpub` is `null`:

```json
{
  "pubkey": "4dc32369...",
  "xpub": "xpub6FnCn..."
}
```

The same optional `tweak` parameter is available on the [`/bip340/sign`](https://docs.sodot.dev/vertex-api-reference/#tag/bip340/POST/bip340/sign) endpoint, so signatures verify under the tweaked public key returned here.

:::danger[Editor note (remove before release)]
The OpenAPI spec documents `tweak` as a hex string on both `derive-tweak-pubkey` endpoints (matching `/bip340/sign`), but in the Vertex source (`src/api/bip340/derive_pubkey.rs`) the field is missing the hex serde adapter, so at runtime these two endpoints actually expect a JSON array of 32 byte values. Verify which encoding ships before release and fix either the docs example above or the Vertex serde.
:::

## Deriving Public Keys from an xPub or sPub

Given an xPub (or sPub), further non-hardened public keys can be derived without touching the Key Share at all.
The Vertex exposes helper endpoints for this, so you can generate additional addresses from a previously fetched xPub or sPub without holding any Key Permission on the original Key:

* [`/ecdsa/derive-pubkey-from-xpub`](https://docs.sodot.dev/vertex-api-reference/#tag/ecdsa/POST/ecdsa/derive-pubkey-from-xpub)
* [`/ed25519/derive-pubkey-from-spub`](https://docs.sodot.dev/vertex-api-reference/#tag/ed25519/POST/ed25519/derive-pubkey-from-spub)
* [`/bip340/derive-tweak-pubkey-from-xpub`](https://docs.sodot.dev/vertex-api-reference/#tag/bip340/POST/bip340/derive-tweak-pubkey-from-xpub) (also accepts the optional `tweak` parameter)

These endpoints require a valid API key but no specific Role, since they perform pure public-key arithmetic and never access stored Key Shares.

```bash
curl -L -X POST 'https://<YOUR_VERTEX>/ecdsa/derive-pubkey-from-xpub' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H 'Authorization: <USER_API_KEY>' \
--data-raw '{
  "xpub": "<BASE58_XPUB>",
  "derivation_path": [0, 7]
}'
```

The response format is identical to the corresponding `derive-pubkey` endpoint of the same algorithm.

:::tip
The derivation path passed to a `*-from-xpub` endpoint is applied **relative to the given xPub**. Deriving path `[44, 60, 0, 0, 0]` from the root Key and deriving `[0, 0]` from the xPub of path `[44, 60, 0]` yield the same public key.
:::

For the error responses returned by all of the endpoints above (e.g. `key_not_found`, `bad_key_permission`), see [Vertex Errors](/vertex/vertex_errors).
