> For the complete documentation index, see [llms.txt](https://docs.bitsafe.finance/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.bitsafe.finance/decentralization-manager/operations-and-reference/api-and-workflow-reference.md).

# API and workflow reference

## Scope

Decentralization Manager serves an HTTP API on the same port as its web interface. This page lists the routes, the request conventions, the workflow model, and the API errors.

The peer and coordinator model is in [Architecture overview](/decentralization-manager/concepts-and-development/architecture-overview.md). Product-wide compatibility and troubleshooting are in [Compatibility, releases, and troubleshooting](/decentralization-manager/operations-and-reference/compatibility-releases-and-troubleshooting.md).

The HTTP API has two parts:

* The operator API serves the web interface and operator scripts.
* The tenant API, under `/v0/tenant/*`, serves wallets.

The peer protocol on the Noise port is not part of the HTTP API. The Canton Admin API, the Canton Ledger API, and the Daml choices are not part of it either. The repository binary is `dec-party-manager`.

## Before you begin

You need:

* A running Decentralization Manager node.
* The base URL of the node, such as `https://decman.example.com`.
* For the operator API, an access token from the configured Keycloak or Auth0 provider.
* For admin-gated routes, the role in `DECPM_ADMIN_ROLE`, when that variable is set.
* For routes that call the Ledger API, party credentials for the target Decentralized Party on this node.
* For the tenant API, a tenant API key from the operator of the node.

{% hint style="warning" %}
Never set `DECPM_INSECURE=true` on a shared or production node. Insecure mode accepts any token, and it skips the tenant API key check. The node refuses to start in insecure mode unless the Canton network is `devnet`. `DECPM_CANTON_NETWORK` sets the network, and its default is `devnet`.
{% endhint %}

## Authentication

Send the operator access token as a bearer token:

```bash
export DECMAN_URL="https://decman.example.com"
export DECMAN_TOKEN="<access-token>"

curl --fail-with-body \
  -H "Authorization: Bearer ${DECMAN_TOKEN}" \
  "${DECMAN_URL}/node-config"
```

Authentication has two layers:

1. The node validates the caller's token against the configured identity provider.
2. Routes that call the Ledger API use the stored party credentials of the target Decentralized Party.

The route tables on this page use these access levels:

| Access     | Meaning                                                                                                  |
| ---------- | -------------------------------------------------------------------------------------------------------- |
| Public     | No token.                                                                                                |
| Token      | A valid operator access token.                                                                           |
| Admin      | A valid token with the role in `DECPM_ADMIN_ROLE`. When the variable is unset, every valid token passes. |
| Tenant key | A key from `DECPM_TENANT_API_KEYS`, sent as `Authorization: Bearer <key>`.                               |

[Authentication and operator roles](/decentralization-manager/operations-and-reference/authentication-and-operator-roles.md) has the full rules. It also covers the first-run bootstrap of `PUT /party-config`, which needs no token.

## OpenAPI access

The node generates an OpenAPI document and a Swagger UI from its HTTP handlers. The node mounts both only in insecure mode:

* Swagger UI: `/swagger-ui/`
* OpenAPI JSON: `/api-docs/openapi.json`

A secure node serves neither route. Do not turn on insecure mode on a shared node to read the document. Read it from a local devnet node instead.

## Request and response conventions

* Send and expect JSON. A DAR upload sends each file as base64 inside the JSON body.
* Canton identifiers are strings, for example `party::1220...` or `participant::1220...`.
* The node accepts request bodies up to 100 MB. The limit exists for DAR uploads.
* Most list routes return arrays inside a response object, such as `runs` or `invitations`. `GET /packages/vetted` returns a bare array.
* The API has no idempotency keys. Read the state before you repeat a write.
* A workflow start returns an `instance_name`. Use it to watch or control that run.

Some read routes return their results in pages:

| Route                         | Page parameters                             | Next page                                                               |
| ----------------------------- | ------------------------------------------- | ----------------------------------------------------------------------- |
| `GET /governance/proposals`   | `limit` (default 50, maximum 200), `cursor` | Send `next_cursor` from the previous response as `cursor`               |
| `GET /governance/audit`       | `limit` (default 50), `offset`              | Raise `offset` by `limit`                                               |
| `GET /governance/chain-audit` | `limit`, `before_offset`                    | Send `next_before_offset` from the previous response as `before_offset` |

## Errors

Most handlers return this error body:

```json
{
  "error": "Human-readable error message"
}
```

`POST /onboarding` returns HTTP `422` when the selected peers do not all list each other, or when the coordinator cannot query a selected peer. The body then has `error` and `missing_edges`. Each entry has `from`, `to`, and `kind`. The `kind` is `mesh_hole` or `unreachable_from_coordinator`.

| Code  | Typical cause                                                                                                                                                                                                  |
| ----- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `400` | A malformed request, or a value that fails validation.                                                                                                                                                         |
| `401` | A missing or invalid token. The `error` text names the cause, such as `missing bearer token`, `token issuer not trusted: <issuer>`, or `token is not active`. A tenant route answers `invalid tenant API key`. |
| `403` | `missing required role: <role>`. The token lacks the admin role.                                                                                                                                               |
| `404` | `No credentials configured for party` on a governance route, or an unknown run or invitation.                                                                                                                  |
| `409` | A conflict, such as another run on the same party, an incompatible peer, or a run in the wrong state.                                                                                                          |
| `422` | The onboarding mesh check failed.                                                                                                                                                                              |

The API has no stable error codes, request IDs, or `retryable` flag. Do not parse the error text to decide a retry.

Before you repeat a write that can change state:

1. Read the resource or the run state.
2. Confirm whether the first request started a run or finished an operation.
3. Use the retry route only for a failed run that is safe to repeat.
4. Escalate when the result is unclear.

## Route reference

### Node and health

| Method | Route                  | Access | Purpose                                                                          |
| ------ | ---------------------- | ------ | -------------------------------------------------------------------------------- |
| GET    | `/healthz`             | Public | Liveness probe. Returns `{"status":"ok"}` and does no I/O.                       |
| GET    | `/auth-config`         | Public | Identity-provider settings for the login page.                                   |
| GET    | `/node-config`         | Token  | Node configuration, `version`, and `build_version`.                              |
| GET    | `/node-health`         | Token  | Health of the Admin API, the Ledger API, the participant, and the synchronizers. |
| GET    | `/participants-status` | Token  | Connection status, latency, and version of each peer.                            |
| GET    | `/keys/status`         | Token  | The Noise public key of this node.                                               |
| GET    | `/network-info`        | Token  | The DSO party and the `AmuletRules` contract.                                    |
| GET    | `/operator-info`       | Token  | The Utility operator party.                                                      |

[Monitoring and logging](/decentralization-manager/operations-and-reference/monitoring-and-logging.md) describes the health responses and the metrics listener.

### Peers

| Method | Route             | Access | Purpose                        |
| ------ | ----------------- | ------ | ------------------------------ |
| GET    | `/network-config` | Token  | The stored peer records.       |
| POST   | `/network-config` | Admin  | Replaces the stored peer list. |

### Party configuration and authentication

| Method | Route                                 | Access | Purpose                                                                   |
| ------ | ------------------------------------- | ------ | ------------------------------------------------------------------------- |
| GET    | `/party-config/{dec_party_id}`        | Token  | The party credentials of one party. Secrets are masked.                   |
| PUT    | `/party-config`                       | Admin  | Stores party credentials. The request accepts no unknown fields.          |
| POST   | `/party-config/discover-member-party` | Admin  | Finds the member party of the user that the given credentials sign in as. |
| GET    | `/auth/status`                        | Token  | The authentication status of each configured party.                       |
| POST   | `/auth/test`                          | Token  | Requests a fresh token for each stored party credential.                  |
| POST   | `/auth/grant-rights`                  | Admin  | Grants Ledger API rights on the member party and the Decentralized Party. |

### Decentralized Parties and membership

| Method | Route                    | Access | Purpose                                                                                    |
| ------ | ------------------------ | ------ | ------------------------------------------------------------------------------------------ |
| GET    | `/decentralized-parties` | Token  | Lists Decentralized Parties. `prefix` filters by party ID prefix.                          |
| POST   | `/onboarding`            | Admin  | Starts a run that creates a Decentralized Party.                                           |
| POST   | `/add-party`             | Admin  | Starts a run that adds a member.                                                           |
| POST   | `/kick`                  | Admin  | Starts a run that removes a member.                                                        |
| POST   | `/change-threshold`      | Admin  | Starts a run that changes the threshold.                                                   |
| DELETE | `/acs-import-quarantine` | Token  | Lifts an ACS import quarantine. Takes `party_id` and `participant_id`. It repairs nothing. |

Each start route also has a legacy status route and a legacy cancel route: `GET /<kind>/status` and `POST /<kind>/cancel`. The kinds are `onboarding`, `add-party`, `kick`, and `change-threshold`.

[Membership and governance changes](/decentralization-manager/operations-and-reference/membership-and-governance-changes.md) and [Add a member to a Decentralized Party](/decentralization-manager/operations-and-reference/add-a-member.md) describe these procedures.

### Workflow runs

| Method | Route                                | Access | Purpose                                              |
| ------ | ------------------------------------ | ------ | ---------------------------------------------------- |
| GET    | `/workflows`                         | Token  | Lists the runs that are not dismissed.               |
| POST   | `/workflows/{instance_name}/cancel`  | Admin  | Cancels an in-flight run that this node coordinates. |
| POST   | `/workflows/{instance_name}/retry`   | Admin  | Retries a failed run that this node coordinates.     |
| POST   | `/workflows/{instance_name}/dismiss` | Admin  | Hides a finished run from the list.                  |

### Invitations

| Method | Route                            | Access | Purpose                                                                                                                                |
| ------ | -------------------------------- | ------ | -------------------------------------------------------------------------------------------------------------------------------------- |
| GET    | `/invitations`                   | Token  | Pending invitations.                                                                                                                   |
| GET    | `/invitations/handled`           | Token  | Accepted and declined invitations, newest first.                                                                                       |
| GET    | `/invitations/{id}/dars/{index}` | Admin  | Downloads one DAR of a pending DAR invitation from the coordinator. The node checks the DAR against the hash that the invitation pins. |
| POST   | `/invitations/accept`            | Admin  | Accepts an invitation. Body: `{"id": "<invitation-id>"}`.                                                                              |
| POST   | `/invitations/decline`           | Admin  | Declines an invitation. Body: `{"id": "<invitation-id>"}`.                                                                             |

### Packages, DARs, and contract deployment

| Method | Route                         | Access | Purpose                                                                                                |
| ------ | ----------------------------- | ------ | ------------------------------------------------------------------------------------------------------ |
| GET    | `/packages`                   | Token  | The package IDs that this node uses.                                                                   |
| GET    | `/packages/vetted`            | Token  | The packages that this participant vets.                                                               |
| GET    | `/packages/compare-peers`     | Token  | Compares the vetted packages of this node with each peer. `participants` takes a comma-separated list. |
| GET    | `/packages/expected-versions` | Token  | The Splice package versions that the DSO `AmuletRules` contract pins.                                  |
| POST   | `/dars/upload`                | Admin  | Uploads DARs to this participant only.                                                                 |
| POST   | `/dars/distribute`            | Admin  | Starts a run that sends DARs to the peers in `peer_ids`.                                               |
| POST   | `/dars/distribute-package`    | Admin  | Starts the same run for the DAR on this node that holds `package_id`.                                  |
| GET    | `/dars/distribute/status`     | Token  | Legacy status of the DAR distribution run.                                                             |
| POST   | `/dars/cancel`                | Admin  | Legacy cancel of the DAR distribution run.                                                             |
| POST   | `/contracts`                  | Admin  | Starts a run that deploys contracts for a Decentralized Party. It uploads no DARs.                     |
| GET    | `/contracts/status`           | Token  | Legacy status of the contracts run.                                                                    |
| POST   | `/contracts/cancel`           | Admin  | Legacy cancel of the contracts run.                                                                    |

[Package and contract operations](/decentralization-manager/operations-and-reference/package-and-contract-operations.md) describes these procedures.

### Governance

The governance routes take a `party_id`, which is the Decentralized Party ID.

| Method | Route                             | Access | Purpose                                                                                            |
| ------ | --------------------------------- | ------ | -------------------------------------------------------------------------------------------------- |
| GET    | `/governance/state`               | Token  | The `GovernanceRules` contract of the party.                                                       |
| GET    | `/governance/confirmations`       | Token  | Open actions and their confirmations. Only an admin caller gets the full proposal payload.         |
| GET    | `/governance/proposals`           | Token  | One page of open proposals.                                                                        |
| GET    | `/governance/known-members`       | Token  | The member parties that each participant knows.                                                    |
| GET    | `/governance/audit`               | Token  | The governance audit trail of this node. Without `party_id`, the newest entries for every party.   |
| GET    | `/governance/chain-audit`         | Token  | Ledger events of the party. `scope=all` reads every event live. `refresh=true` reads Canton again. |
| POST   | `/governance/propose`             | Admin  | Creates a proposal. The node also creates its own confirmation.                                    |
| POST   | `/governance/confirm`             | Admin  | Confirms an action.                                                                                |
| POST   | `/governance/execute`             | Admin  | Executes an action that has enough confirmations.                                                  |
| POST   | `/governance/expire`              | Admin  | Expires a stale confirmation.                                                                      |
| POST   | `/governance/cancel`              | Token  | Revokes a confirmation that this node made.                                                        |
| POST   | `/governance/cancel-proposal`     | Admin  | Retracts a proposal that this node created, together with its confirmation.                        |
| GET    | `/coupon-reassignment-delegation` | Token  | The active reward delegation contracts of the party.                                               |

`POST /governance/propose` takes `party_id`, `rules_contract_id`, and a `proposal` object. The OpenAPI document describes each proposal type. [Governance lifecycle](/decentralization-manager/concepts-and-development/governance-lifecycle.md) explains the proposal, confirmation, and execution steps.

Retract a proposal and its confirmation:

```bash
curl --fail-with-body \
  -X POST "${DECMAN_URL}/governance/cancel-proposal" \
  -H "Authorization: Bearer ${DECMAN_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{
    "party_id": "<decentralized-party-id>",
    "proposal_cid": "<proposal-contract-id>",
    "confirmation_cid": "<own-confirmation-contract-id>"
  }'
```

`confirmation_cid` is optional. The node archives that confirmation in the same transaction.

### Contracts and services

The `GET` routes in this table take a `party_id` and query the Ledger API as that party.

| Method | Route                                                                                         | Access | Returns                                                                                       |
| ------ | --------------------------------------------------------------------------------------------- | ------ | --------------------------------------------------------------------------------------------- |
| GET    | `/contracts/query`                                                                            | Token  | Contract IDs by template or by interface. `include_payload=true` adds the decoded fields.     |
| GET    | `/services/provider`, `/services/user`, `/services/registrar`                                 | Token  | Utility service contracts.                                                                    |
| GET    | `/credential-offers`, `/credentials`                                                          | Token  | Credential contracts.                                                                         |
| GET    | `/registrar-service-requests`, `/provider-configurations`, `/instruments`                     | Token  | Registry contracts.                                                                           |
| GET    | `/holdings`, `/transfer-preapprovals`, `/transfer-factories`                                  | Token  | Token-standard contracts.                                                                     |
| GET    | `/governance/transfer-instructions`, `/governance/mint-requests`, `/governance/burn-requests` | Token  | Pending token-standard requests.                                                              |
| POST   | `/token-standard-contracts`                                                                   | Admin  | Forwards the request body to a fixed external token-standard service. It takes no `party_id`. |

`/contracts/query` takes `package_id`, `module_name`, and `entity_name`. Set `interface=true` for an interface query.

### External parties and the tenant API

| Method | Route                                      | Access     | Purpose                                                                                |
| ------ | ------------------------------------------ | ---------- | -------------------------------------------------------------------------------------- |
| GET    | `/external-parties`                        | Token      | The external parties that this participant hosts.                                      |
| POST   | `/v0/tenant/prepare`                       | Tenant key | Builds the onboarding topology of a new external party and returns the hashes to sign. |
| POST   | `/v0/tenant/execute`                       | Tenant key | Checks the signed onboarding topology, co-signs it, and submits it.                    |
| GET    | `/v0/tenant/{party}/status`                | Tenant key | Reports whether this host hosts the party yet.                                         |
| GET    | `/v0/tenant/{party}/state`                 | Tenant key | The current serial, threshold, and host count of the party.                            |
| POST   | `/v0/tenant/add-hosts/prepare`             | Tenant key | Builds the topology that adds hosts to an external party.                              |
| POST   | `/v0/tenant/add-hosts/execute`             | Tenant key | Checks the signed add-hosts topology, co-signs it, and submits it.                     |
| POST   | `/v0/tenant/add-hosts/authorize`           | Tenant key | Adds hosts to a party whose namespace is the key of a participant.                     |
| GET    | `/v0/tenant/{party}/acs/{target}`          | Tenant key | Serves one block of the ACS of the party for a joining host. `seq` selects the block.  |
| POST   | `/v0/tenant/add-hosts/import`              | Tenant key | Imports one relayed ACS block on the joining host.                                     |
| POST   | `/v0/tenant/threshold/prepare`             | Tenant key | Builds a change of the confirmation threshold.                                         |
| POST   | `/v0/tenant/threshold/execute`             | Tenant key | Submits the signed threshold change.                                                   |
| POST   | `/v0/tenant/threshold/authorize`           | Tenant key | Changes the threshold of a party whose namespace is the key of a participant.          |
| POST   | `/v0/tenant/local-party/adopt-key/prepare` | Tenant key | Builds the conversion that gives a local party an owner-held signing key.              |
| POST   | `/v0/tenant/local-party/adopt-key/execute` | Tenant key | Co-signs and submits the signed conversion.                                            |

The tenant API does not use the operator token or the admin role. The node reads its tenant keys from `DECPM_TENANT_API_KEYS`. With no keys, the node answers every tenant call with HTTP `401`.

Every wallet-signed tenant write takes two calls. The `prepare` call returns the hashes that the wallet signs. The `execute` call submits the signed topology. The private key of the party stays in the wallet. The node receives only public keys and signatures.

Releases up to v1.13.0 serve the four submit routes under `…/onboard`:

| Current route                              | Route in v1.13.0 and earlier               |
| ------------------------------------------ | ------------------------------------------ |
| `/v0/tenant/execute`                       | `/v0/tenant/onboard`                       |
| `/v0/tenant/add-hosts/execute`             | `/v0/tenant/add-hosts/onboard`             |
| `/v0/tenant/threshold/execute`             | `/v0/tenant/threshold/onboard`             |
| `/v0/tenant/local-party/adopt-key/execute` | `/v0/tenant/local-party/adopt-key/onboard` |

The [`decman-wallet` crate](https://github.com/DLC-link/decentralization-manager/blob/main/crates/decman-wallet/README.md) is a Rust client for the tenant API. Its `TenantClient` calls one host, and its flow functions run the complete procedures. The function `execute_co_validated` was `onboard_co_validated` in v1.13.0.

The procedures are in [Decentralize an external party](/decentralization-manager/operations-and-reference/decentralize-an-external-party.md) and [Decentralize an existing party](/decentralization-manager/operations-and-reference/decentralize-an-existing-party.md).

## Workflow model

### Workflow kinds

The node stores six workflow kinds:

* `Onboarding`
* `Kick`
* `Contracts`
* `Dars`
* `AddParty`
* `ChangeThreshold`

A run has the role `Coordinator` or `Peer`. The coordinator starts and drives the run. A peer accepts an invitation and runs its local steps when the coordinator asks.

A node can run several workflow runs at the same time, also of the same kind. A node refuses to start a `Kick`, `AddParty`, `ChangeThreshold`, or `Contracts` run for a party that already has a run in progress on that node. The node counts its runs in either role. Runs for different parties can run at the same time. The guard is local to each node. Decentralization Manager does not stop two different nodes from coordinating conflicting runs on the same party.

### Workflow status values

The status values on the wire are:

| Value        | Meaning                                                               | Operator action                                                                                        |
| ------------ | --------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
| `idle`       | No run has started. Only the legacy per-kind status routes return it. | Start the workflow when the prerequisites are met.                                                     |
| `inprogress` | The run is active or waits for peers.                                 | Read `current_step`, the peer progress, and the invitations. Do not send the same start request again. |
| `completed`  | The run reached its success state.                                    | Verify the Canton topology, packages, or contracts.                                                    |
| `failed`     | The run stopped with an error.                                        | Read `error`, correct the cause, and retry only when it is safe.                                       |
| `cancelled`  | An operator or the coordinator cancelled the run.                     | Confirm the peer state before you start a replacement run.                                             |

The workflow status has no `ready`, `executing`, or `expired` values. The `current_step` value shows finer progress. Governance confirmation expiry is separate from the workflow status.

### Start response

A successful start returns HTTP `202` with this body:

```json
{
  "status": "inprogress",
  "message": "<human-readable message>",
  "instance_name": "<workflow-instance>"
}
```

Store `instance_name`. The legacy per-kind status and cancel routes cannot choose between concurrent runs of the same kind.

### Run fields

`GET /workflows` returns a `runs` array. Each run has these fields:

* `instance_name`, `kind`, `role`, and `status`.
* `current_step`, `step_index`, and `step_total`.
* `expected_peers`, `completed_peers`, and `connected_peers`.
* `error`, when the run failed, or when a cancel gave a reason.
* `acs_progress`, while an ACS transfer moves.
* Context fields, such as `dec_party_id`, `prefix`, `participants`, `previous_threshold`, `new_threshold`, `kicked_participant`, `added_participant`, `package_names`, and `dar_filenames`.
* `coordinator_name` on peer runs.
* `dismissed`, `created_at`, and `updated_at`. The times are Unix seconds.

The API does not return the stored start configuration of a run.

### General workflow sequence

1. Validate the peer records, the authentication, the Canton access, and the inputs of the workflow.
2. Send the start request to the coordinator.
3. Store the returned `instance_name`.
4. The other participants read and accept their invitations.
5. Poll `GET /workflows` and find the run by `instance_name`.
6. Wait for `completed`, `failed`, or `cancelled`.
7. Verify the resulting Canton state or the deployed artifact.

The node stores the run progress in SQLite. At startup, it resumes every run that is `inprogress`. Recovery has workflow-specific limits. Read the operations guides before you rely on it.

## Example: start and watch onboarding

Create a Decentralized Party with selected peers:

```bash
curl --fail-with-body \
  -X POST "${DECMAN_URL}/onboarding" \
  -H "Authorization: Bearer ${DECMAN_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{
    "party_id_prefix": "example-party",
    "peer_ids": [
      "participant-2::1220...",
      "participant-3::1220..."
    ]
  }'
```

The optional `threshold` field sets the initial threshold. Without it, the coordinator uses half the owner count, rounded up, with a minimum of 1.

Example response:

```json
{
  "status": "inprogress",
  "message": "Onboarding workflow started",
  "instance_name": "<workflow-instance>"
}
```

Poll the run list and select the returned run:

```bash
curl --fail-with-body \
  -H "Authorization: Bearer ${DECMAN_TOKEN}" \
  "${DECMAN_URL}/workflows"
```

Do not treat the `message` text or the `instance_name` format as stable. Only the documented fields and the exact enum values can drive client logic.

## Workflow control

Use the instance-scoped routes. They act on exactly one run:

* `POST /workflows/{instance_name}/cancel` cancels an in-flight run that this node coordinates. Otherwise it returns `409`.
* `POST /workflows/{instance_name}/retry` restarts a `failed` coordinator run at the step that failed. Otherwise it returns `409`.
* `POST /workflows/{instance_name}/dismiss` hides a finished run. It returns `409` while the run is `inprogress`.

A peer cannot retry its own run. The peer run returns to `inprogress` when the coordinator retries.

Read the latest run state before a cancel or a retry. A coordinator action can also change the peer runs and the pending invitations. Never assume that a step is safe to repeat after a partial Canton submission.

## Invitations

Read the pending invitations:

```bash
curl --fail-with-body \
  -H "Authorization: Bearer ${DECMAN_TOKEN}" \
  "${DECMAN_URL}/invitations"
```

Accept an invitation by its `id`:

```bash
curl --fail-with-body \
  -X POST "${DECMAN_URL}/invitations/accept" \
  -H "Authorization: Bearer ${DECMAN_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{"id":"<invitation-id>"}'
```

A peer declines an invitation through `POST /invitations/decline` with the same body. A decline fails the matching coordinator run when the invitation carries the `instance_name` of the coordinator's run.

## Client implementation checklist

* [ ] Pin the client to a release, and read the OpenAPI document of that release.
* [ ] Use bearer authentication and least-privilege roles.
* [ ] Store the `instance_name` of each run.
* [ ] Match exact enum values, not human-readable messages.
* [ ] Read the state before you repeat a write.
* [ ] Poll with backoff and a client-side deadline.
* [ ] Keep tokens, client secrets, tenant keys, party credentials, and contract payloads out of logs.
* [ ] Verify the Canton result after a completed run.
* [ ] Test restart, cancellation, peer outage, and partial progress.

## Troubleshooting

| Symptom                                                                                     | Likely cause                                                                                  | Next action                                                                                                                                             |
| ------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `401` with a token error                                                                    | The token is missing or expired, the issuer is not trusted, or the provider discovery failed. | Check the Keycloak or Auth0 settings, the token expiry, and the reachability of the provider.                                                           |
| `401` `invalid tenant API key`                                                              | The key is not one of the keys of this host, or the host has no keys.                         | Send the key of this host. Check `DECPM_TENANT_API_KEYS` on the host.                                                                                   |
| `403` `missing required role: <role>`                                                       | The token lacks the role in `DECPM_ADMIN_ROLE`.                                               | Grant the role, or fix the role claim. Do not remove the role gate as a workaround.                                                                     |
| `409` `Party <id> already has a <kind> workflow in flight (run <run>)`                      | Another run on this node targets the same party.                                              | Wait for that run to end, or cancel it.                                                                                                                 |
| `409` `Cannot start the workflow: every invited peer must run dec-party-manager >= 0.1.9 …` | The named peers run a version below 0.1.9, or the coordinator could not read their version.   | Read the reason next to each peer. Upgrade the peer to the release of the other nodes, bring it online, or deselect it.                                 |
| `409` `Retry must be initiated from the coordinator side. …`                                | The retry went to a peer run.                                                                 | Retry the run on the coordinator.                                                                                                                       |
| `409` `Cannot retry a workflow in status …; only Failed runs can be retried`                | The run is not `failed`.                                                                      | Read the run state. Cancel or wait instead.                                                                                                             |
| `422` with `missing_edges`                                                                  | The selected peers do not all list each other, or the coordinator cannot query a peer.        | For `mesh_hole`, add `to` as a peer on the `from` node. For `unreachable_from_coordinator`, fix the coordinator's record of `to`, or bring `to` online. |
| A run fails with `<step> cannot complete: peer <id> has been unreachable for <n>s`          | The coordinator heard nothing from the peer for 10 minutes, and the run lost its quorum.      | Bring the peer back online. Then retry the run.                                                                                                         |
| A run stays `inprogress`                                                                    | A peer has not accepted, connected, or finished the current step.                             | Read `current_step`, `expected_peers`, `connected_peers`, `/invitations`, and `/participants-status`.                                                   |
| A retry can repeat work                                                                     | The client lost the first response, or the run failed after a partial Canton operation.       | Read `/workflows` and verify the Canton state before you retry. Escalate if the result stays unclear.                                                   |
| The Swagger UI is missing                                                                   | The node runs in secure mode.                                                                 | Read the OpenAPI document from a local devnet node in insecure mode.                                                                                    |

## Technical sources

* [HTTP server and route registration](https://github.com/DLC-link/decentralization-manager/blob/main/crates/decman/src/server/mod.rs)
* [HTTP handlers](https://github.com/DLC-link/decentralization-manager/tree/main/crates/decman/src/server/handlers)
* [Authentication middleware](https://github.com/DLC-link/decentralization-manager/blob/main/crates/decman/src/server/middleware/auth.rs)
* [Shared HTTP DTOs](https://github.com/DLC-link/decentralization-manager/blob/main/crates/common/src/api.rs)
* [Shared workflow types](https://github.com/DLC-link/decentralization-manager/blob/main/crates/common/src/types.rs)
* [Server DTOs](https://github.com/DLC-link/decentralization-manager/blob/main/crates/decman/src/server/types.rs)
* [Repository README, API endpoints](https://github.com/DLC-link/decentralization-manager/blob/main/README.md)
* [Decentralizing an external party](https://github.com/DLC-link/decentralization-manager/blob/main/docs/DECENTRALIZING_AN_EXTERNAL_PARTY.md)
* [decman-wallet README](https://github.com/DLC-link/decentralization-manager/blob/main/crates/decman-wallet/README.md)

## Related pages

* [Authentication and operator roles](/decentralization-manager/operations-and-reference/authentication-and-operator-roles.md)
* [Package and contract operations](/decentralization-manager/operations-and-reference/package-and-contract-operations.md)
* [Membership and governance changes](/decentralization-manager/operations-and-reference/membership-and-governance-changes.md)
* [Monitoring and logging](/decentralization-manager/operations-and-reference/monitoring-and-logging.md)
* [Backup, recovery, and upgrades](/decentralization-manager/operations-and-reference/backup-recovery-and-upgrades.md)
* [Compatibility, releases, and troubleshooting](/decentralization-manager/operations-and-reference/compatibility-releases-and-troubleshooting.md)
* [Security architecture](/decentralization-manager/operations-and-reference/security-architecture.md)

## Next step

👉 **Secure API access:** [Authentication and operator roles](/decentralization-manager/operations-and-reference/authentication-and-operator-roles.md).


---

# 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 by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.bitsafe.finance/decentralization-manager/operations-and-reference/api-and-workflow-reference.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

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.
