> For the complete documentation index, see [llms.txt](https://docs.catalyx.solutions/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.catalyx.solutions/catalyx-blockchain-manager/canton-network/version-2.0/validator-management/external-and-multi-host-parties.md).

# External & Multi-Host Parties

Onboard parties whose signing keys live outside the participant, and host a single party across several participants.

Canton parties normally have their keys held by the participant that hosts them. Two capabilities change that, and they compose:<br>

1. **External parties:** The party's signing key lives *outside* the participant — with the party's owner. The participant cannot act on the party's behalf; the owner signs its own transactions.
2. **Multi-hosting:** A single party is hosted on *several* participants, which may belong to different organisations. The party survives the loss of any one of them.

### External parties and how they work

For the concept of external parties and the difference with local parties, please refer to the Canton documentation:

{% embed url="<https://docs.canton.network/overview/reference/external-party#external-party>" %}

### Why multi-host and how it works

For the concept and Canton's own guidance on resilience and disaster-recovery use cases, see Multi-Hosting and Resilience in the Canton documentation:

{% embed url="<https://docs.canton.network/appdev/deep-dives/multi-hosting#why-multi-host>" %}

***

## Onboarding an external party

Start from **Parties → Onboard External Party** on the validator.

{% stepper %}
{% step %}
**Identity — the party's key**

*Provide the party's public key. The participant will generate topology transactions for you to sign.*

<div data-with-frame="true"><figure><img src="https://2680825251-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsUGPGTcyMu8FXsdY8XQY%2Fuploads%2Fgit-blob-c7ed1085ab9b5565795a91198fafbef86314f322%2Fimage%20(178).png?alt=media" alt=""><figcaption></figcaption></figure></div>

| Field                       | Notes                                                                                                     |
| --------------------------- | --------------------------------------------------------------------------------------------------------- |
| **Party hint**              | 2–64 characters, letters, digits, hyphens, and underscores only. Incorporated into the generated party ID |
| **Key algorithm**           | **Ed25519 (recommended)** or **ECDSA P-256**                                                              |
| **Public key (DER Base64)** | X.509 SubjectPublicKeyInfo, DER encoded, then Base64                                                      |

The wizard shows the commands to produce a key pair:

```bash
openssl genpkey -algorithm ed25519 -out key.pem
openssl pkey -in key.pem -pubout -outform DER | base64 -w 0
```

Nothing is sent to the participant at this step. Click **Next: Hosting →**.

{% hint style="warning" %}
`key.pem` is the party's private key. Whoever holds it controls the party. Generate it on the party owner's own machine wherever possible, and store it in a secrets manager or hardware token — not alongside your platform configuration.
{% endhint %}
{% endstep %}

{% step %}
**Hosting — choose the host set**

*Choose which participants host this party. This cannot be changed later — the host set is covered by the signature.*

<div data-with-frame="true"><figure><img src="https://2680825251-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsUGPGTcyMu8FXsdY8XQY%2Fuploads%2Fgit-blob-abae42f0f766cad6314a76ae3dc5437fff2c80cc%2Fimage%20(179).png?alt=media" alt=""><figcaption></figcaption></figure></div>

Leave this step untouched to host the party on your validator alone. Otherwise:

* **Add participant** adds a row. Enter the participant UID in `alias::fingerprint` form, and choose **Confirming** or **Observing**.
* Tick **This validator observes only (does not confirm)** if confirmation should rest entirely on the other hosts.
* Set the **Confirmation threshold**. The hint below it tells you how many confirming participants you currently have.

Participant UIDs are entered as free text rather than chosen from a list — a production synchronizer carries hundreds of participants, and the useful ones are usually on other clusters. A participant UID is a public identifier; naming one needs no credentials for that node.

**The advisory lookup.** When you leave a UID field, CatalyX checks it against the synchronizer and reports:

| Chip                                                                                               | Meaning                        |
| -------------------------------------------------------------------------------------------------- | ------------------------------ |
| *Checking synchronizer…*                                                                           | Lookup in flight               |
| *Known on this synchronizer*                                                                       | The participant exists         |
| *This is this validator — remove it, it is already a host*                                         | You named your own participant |
| *Not found on this synchronizer… You can continue, but allocation will fail unless it joins first* | No match                       |

{% hint style="warning" %}
**The lookup warns; it never blocks.** Naming a participant that has not yet joined the synchronizer is legitimate — but the party's signature is spent at the next step, so a genuine typo costs you the whole onboarding. Resolve every warning before continuing.

All hosts must be on the **same synchronizer**. A participant that is absent from your local topology store — including one whose validator has been offline long enough to fall behind — will not resolve, and allocation will fail.
{% endhint %}

Click **Generate Transactions →**.
{% endstep %}

{% step %}
**Sign the multi-hash**

*Sign the hash below with your private key and paste the Base64 signature.*

The participant has generated the party ID and a **multi-hash** covering the topology transactions. When you named co-hosts, a **Co-hosts** line reports how many additional participants must authorize.

Give the multi-hash to the party's key holder to sign. The wizard shows the command for the chosen algorithm:

```bash
echo "<multi-hash>" | base64 --decode > hash.bin
openssl pkeyutl -sign -inkey key.pem -rawin -in hash.bin | base64
```

Paste the Base64 signature into **Signature (Base64)** and click **Complete Onboarding**.

{% hint style="danger" %}
This is the point of no return for the host set. If allocation fails because a named participant does not exist, the signature is consumed — you cannot retry with a corrected host list. Start again with a **fresh party hint**.
{% endhint %}
{% endstep %}

{% step %}
**Distribute — wait for the co-hosts**

Single-hosted, the wizard reports **External Party Onboarded** — *Hosted on this validator alone. The party is ready to use.*

Multi-hosted, it reports **Awaiting Other Hosts** and lists each participant still owing approval:

> The party is **not usable yet**. Each participant above must approve hosting it. The request is already visible to them — it appears under Hosting Proposals on their own Parties tab, whether they are in this cluster or another one. Nothing needs to be sent to them.

Click **Done**.
{% endstep %}
{% endstepper %}

***

## Approving a hosting proposal

This is the other half of the workflow, performed by each co-host's operator.

{% stepper %}
{% step %}
**Open Parties → Hosting Proposals**

The proposal is already there. Nothing was sent to you and there is nothing to import — the synchronizer's topology store is shared, and the proposal already carries the party's signature.
{% endstep %}

{% step %}
**Check what you are agreeing to**

The row shows the party ID, every named host with your own participant tagged **this participant**, and the confirmation threshold.

{% hint style="warning" %}
Approving means this participant will store that party's data and take part in confirming its transactions. Only approve proposals you recognise.
{% endhint %}
{% endstep %}

{% step %}
**Click Approve**

There is no confirmation dialog. A toast reports either *Hosting approved — the party is now active* or *Hosting approved — still waiting on other hosts*.

Rows where this participant has already authorized show *Waiting on other hosts* instead of a button.
{% endstep %}
{% endstepper %}

{% hint style="info" %}
**Approval is safe to repeat.** Re-submitting an identical approval succeeds rather than erroring, so retrying after a network failure is harmless.

**A participant is only asked to approve when it takes on more responsibility** — when it is being added as a host, or when its permission is being strengthened. If you are named in a proposal but see no **Approve** button, nothing is required of you.
{% endhint %}

***

## Changing a party's hosting

{% hint style="info" %}
**Version note.** Hosting amendments were added after 2.0.0 and are newer than the onboarding flow above. Exercise them in a non-production environment first.
{% endhint %}

Hosting on an existing party can be changed: add a host, remove one, change a permission, or change the threshold. All four are the same operation — the party's hosting mapping is replaced at the next serial.

Open **Parties → Hosted Parties**, expand the party, and click **Edit hosting**.

<div data-with-frame="true"><figure><img src="https://2680825251-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsUGPGTcyMu8FXsdY8XQY%2Fuploads%2Fgit-blob-207c76dbe21344117f63eb9de925289c9d50fc15%2Fimage%20(180).png?alt=media" alt=""><figcaption></figcaption></figure></div>

{% stepper %}
{% step %}
**Edit Hosting**

*Replace the full set of participants hosting this party. Anything removed here stops hosting it.*

The current host set and threshold are pre-filled. Edit them, then click **Prepare Change →**.

{% hint style="danger" %}
**This is a replacement, not a delta.** What you leave in the list becomes the party's complete new host set — anything you remove stops hosting the party. At least one host must remain.
{% endhint %}
{% endstep %}

{% step %}
**Sign the Change**

*Sign the transaction hash with the party's private key and paste the Base64 signature.*

The modal shows the serial transition — `current → next` — and a transaction hash to sign, with the matching `openssl` command. Paste the signature and click **Submit Change**.

{% hint style="warning" %}
Check the **Key algorithm** selector matches the party's actual key. It defaults to Ed25519 and does not detect the party's algorithm, so an ECDSA P-256 party needs the selector changed or the signature will be rejected.
{% endhint %}
{% endstep %}

{% step %}
**Wait for approvals**

A toast confirms *Hosting change submitted at serial `n` — awaiting approval from affected participants*.

As with onboarding, every participant taking on more responsibility must approve from its own **Hosting Proposals** tab before the change takes effect.
{% endstep %}
{% endstepper %}

### Not supported

{% hint style="warning" %}
**Multi-hosting a participant-managed party.** A party allocated with **Allocate Party** is managed by the participant, which holds its keys. There is no external key holder to sign a hosting change, so its hosting cannot be amended through this flow — which is why **Edit hosting** only appears for externally-signed parties.

If you need a party hosted on more than one participant, onboard it as an external party from the start.
{% endhint %}

***

## Things to know

Behaviour established by testing against a live network:

<table><thead><tr><th width="330">Question</th><th>Answer</th></tr></thead><tbody><tr><td>Does generating the topology validate that a named participant exists?</td><td><strong>No.</strong> It succeeds for an unknown UID; allocation then fails — <em>after</em> the party has signed.</td></tr><tr><td>Is a multi-hosted mapping effective before all hosts authorize?</td><td><strong>No.</strong> It exists as a proposal and is absent from effective state. The party is unusable until the last host approves.</td></tr><tr><td>Is approval idempotent?</td><td><strong>Yes.</strong> Replaying an identical approval succeeds. Re-approving is safe.</td></tr><tr><td>Can the onboarding flow amend an existing party?</td><td><strong>No.</strong> It always creates a party at the first serial. Use <strong>Edit hosting</strong> instead.</td></tr><tr><td>Is a proposal visible to participants that did not submit it?</td><td><strong>Yes.</strong> The synchronizer's topology store is fully shared — a single query returns hundreds of proposals, nearly all naming participants the querying node has no relationship with.</td></tr><tr><td>Do stored proposals carry the party's signature?</td><td><strong>Yes.</strong> Which is why nothing has to be transferred between operators.</td></tr></tbody></table>

Additional notes:

* **Topology propagation is not instant.** Immediately after an approval, a party may still read as pending. The UI polls for up to 30 seconds; if in doubt, refresh the Hosted Parties list.
* **A blank permission in the advisory lookup is normal.** Per-participant synchronizer terms are optional in Canton; whether the participant is *on* the synchronizer is the signal that matters.
* **Naming your own validator as a co-host is not blocked.** The lookup warns you, but nothing prevents it — remove the row.

## Related

* [Parties tab](/catalyx-blockchain-manager/canton-network/version-2.0/console-guide-canton/validators/parties.md) — the UI screens in detail
* [Wallet Gateway](/catalyx-blockchain-manager/canton-network/version-2.0/validator-management/wallet-gateway.md) — custodial key holding for a party, intended to eventually replace the manual signing step above


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.catalyx.solutions/catalyx-blockchain-manager/canton-network/version-2.0/validator-management/external-and-multi-host-parties.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
