Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

NeoPRISM Documentation

Welcome to the NeoPRISM documentation site!

Use the navigation panel on the left to browse different sections of the documentation, including guides, references, and community resources.

Useful links

NeoPRISM & Support

Publicly Available Instances

Note: The public NeoPRISM instances below are personal deployments by the project author, intended for quick evaluation and testing. Please do not use them for production purposes.

External Resources

NeoPRISM Installation

NeoPRISM can be installed and run using either Docker or Nix. Choose the method that best fits your environment.

Note: During development and testing, NeoPRISM typically uses between 10–100 MB of memory. No special hardware requirements are expected.

NeoPRISM also supports advanced deployment modes and Cardano data sources (such as DB Sync and testnet environments). For details on advanced configurations, see the relevant documentation pages.

Docker Installation

This guide will help you install and run a NeoPRISM node using Docker.

Prerequisites

Steps (Mainnet Relay Example)

  1. Clone the NeoPRISM repository:

    git clone https://github.com/hyperledger-identus/neoprism.git
    cd neoprism/docker/mainnet-relay
    
  2. Start NeoPRISM and PostgreSQL using Docker Compose:

    docker-compose up
    
  3. Access the Web UI:

  4. Resolve a DID using the API:

    curl http://localhost:8080/api/dids/<did>
    

Note: The example above demonstrates one way to run NeoPRISM using Docker. You can find additional deployment examples and configurations in the docker directory of the repository.

If you are deploying NeoPRISM in a production environment, please take extra care to harden your setup according to your organization’s security requirements.

Nix Installation

NeoPRISM can be built and run using Nix flakes.

Prerequisites

Steps

  1. Build the NeoPRISM binary from the remote flake:

    nix build github:hyperledger-identus/neoprism/<TAG>#neoprism-bin
    
    • The resulting binary will be located in ./result/bin/neoprism-node.
  2. Build the UI assets from the remote flake (in a separate output directory):

    nix build github:hyperledger-identus/neoprism/<TAG>#neoprism-ui-assets -o ./result-ui-assets
    
    • The UI assets will be available in ./result-ui-assets.
  3. Run NeoPRISM and link the UI assets:

    • Use the --assets-path flag to specify the UI assets directory:

      ./result/bin/neoprism-node indexer --assets-path ./result-ui-assets/assets [options]
      
    • For details on available commands and options, see the CLI help:

      ./result/bin/neoprism-node indexer --help
      
  4. Access the Web UI:

NeoPRISM Architecture

NeoPRISM supports multiple roles within its system architecture:

  • Indexer: Reads, validates, and indexes DID operations from the Cardano blockchain.
  • Submitter: Batches and submits signed DID operations to the Cardano blockchain.
  • Standalone: Runs both indexer and submitter in a single process for simple deployments.

NeoPRISM acts as an indexer by reading DID operations from the Cardano blockchain, validating them, and storing them in a local PostgreSQL database. It organizes these operations using keys such as DIDs or storage hashes. When a user requests the current state of a DID, NeoPRISM replays the relevant operations to reconstruct and return the latest state via its REST API.

In its role as a submitter, NeoPRISM receives signed DID operations and batches them into Cardano transaction metadata. It does not manage private keys for either DID operations or Cardano wallets. The metadata is sent to the wallet component (currently supporting only cardano-wallet) for publishing. This process is stateless and requires the wallet passphrase, along with other related wallet configurations, which are provided through CLI options or environment variables.

Closed-loop standalone deployment

In this mode, both the indexer and submitter run in the same process, which is suitable for a small and simple deployment setup. You may also add a reverse proxy to handle authentication and routing for the submitter API paths.

DID controllerVerifierCardano relay nodeDeploymentNeoPRISM StandaloneCardano HTTP walletCardano block-producer nodePostgreSQL  create transactions  read / write indexed operationssubmit transactionsstream operations using Ourasubmit signed PRISM operationsresolve DID documentspropagate blocks

















Closed-loop indexer - submitter deployment

In this deployment mode, the indexer and submitter run as separate processes, which may be hosted on different machines. This separation allows for independent scaling of each component; for example, multiple indexer instances can be deployed to support high read volume.

  • The indexer process reads, validates, and indexes DID operations from the Cardano blockchain, storing them in a shared PostgreSQL database.
  • The submitter process is stateless and receives signed DID operations, batching and submitting them to the Cardano blockchain via the wallet component. It does not use the database.

A reverse proxy is recommended to route requests to the appropriate service, handling authentication and API path routing for both the indexer and submitter.

DID controllerVerifierCardano relay nodeIndexer DeploymentSubmitter DeploymentNeoPRISM IndexerPostgreSQLNeoPRISM SubmitterCardano HTTP walletCardano block-producer node    read / write indexed operationsstream operations using Ouraresolve DID documentscreate transactionssubmit transactionssubmit signed PRISM operationspropagate blocks



















Open-loop Indexer-only and Submitter-only deployments

NeoPRISM also supports deploying only a subset of its components, depending on your use case and requirements:

  • Indexer-only deployment:
    Only the indexer process is deployed. This setup allows you to read, validate, and index DID operations from the Cardano blockchain, and serve DID resolution requests via the REST API. No submission of new DID operations to the blockchain is possible in this mode.

  • Submitter-only deployment:
    Only the submitter process is deployed. This setup allows you to batch and submit signed DID operations to the Cardano blockchain via the wallet component. DID resolution and indexing are not available in this mode.

These deployment options provide flexibility for scenarios where you may only need to resolve DIDs (indexer-only) or only need to submit new DID operations (submitter-only), without running the full NeoPRISM stack.

Note: These modes are subsets of the closed-loop indexer–submitter deployment, and can be scaled or combined as needed.

Configuration

NeoPRISM nodes offer flexible configuration to suit various deployment scenarios.

This section explains the key configuration options.
For a complete list of available options, see CLI Options.

To start NeoPRISM node in each mode, use one of the following subcommands:

Usage: neoprism-node <COMMAND>

Commands:
  indexer           Start the node in indexer mode
  submitter         Start the node in submitter mode
  standalone        Start the node in standalone mode
  generate-openapi  Generate OpenAPI specification for the API
  help              Print this message or the help of the given subcommand(s)

Options:
  -h, --help     Print help
  -V, --version  Print version

The standalone mode combines both indexer and submitter functionalities. You can refer to the configuration options for each mode and apply them together when using standalone.

Indexer Configuration

The Indexer node monitors the Cardano blockchain for PRISM DID operations, validates and indexes them, and enables efficient lookup of DID Documents.
It is typically used for DID resolution and verification services.

DLT Source

The Indexer node supports multiple DLT sources for ingesting DID operations:

  • Oura:
    Connects to a Cardano relay node and streams block data in real time.

    • Key options:
      • Cardano network: --cardano-network or NPRISM_CARDANO_NETWORK
      • Relay address: --cardano-relay-addr or NPRISM_CARDANO_RELAY_ADDR
  • DB-Sync:
    Connects to a Cardano DB-Sync instance and polls for new blocks and transactions.

    • Key options:
      • DB-Sync URL: --db-sync-url or NPRISM_DB_SYNC_URL
      • Poll interval: --db-sync-poll-interval or NPRISM_DB_SYNC_POLL_INTERVAL
  • Common DLT Source Options:

    • Index interval: --index-interval or NPRISM_INDEX_INTERVAL
    • Confirmation blocks: --confirmation-blocks or NPRISM_CONFIRMATION_BLOCKS

DLT Source Comparison

Oura

Oura works by performing a chainsync protocol with a Cardano relay node. This setup is quite lean, as you can connect to any available public relay. The downside is that sync progress can be slow, since it performs a full sync from the blockchain. If possible, connect to a Cardano node close to your location, as syncing across different geographic regions can be very slow. The initial sync may take multiple days. The best option is to connect to your own Cardano node within the same network for optimal performance.

DB Sync

DBSync is a service that syncs the Cardano blockchain and writes the data to a PostgreSQL database. DBSync is known to be resource-heavy and requires significant disk space. The advantage is that sync speed is very fast, since NeoPRISM only needs to read the database tables and parse the operations. If you can afford to run DBSync, it is recommended to use this option, as the initial sync is much faster compared to Oura.


How Common DLT Source Configuration Works

NeoPRISM streams blocks from the Cardano blockchain and extracts PRISM metadata, which is then persisted to the database. These operations are initially stored as raw, unindexed data. At every configured interval (set by the index interval option), NeoPRISM wakes up and picks up unindexed operations from the database. It then runs the indexing logic, which extracts, validates, and transforms each raw operation into an efficient lookup data structure.

A faster index interval reduces the lag between when an operation is streamed and when it becomes indexed and available for fast lookup. However, setting a very short interval can put additional pressure on the database due to more frequent indexing cycles. NeoPRISM comes with a sensible default value for the index interval to balance performance and resource usage.

Choose the DLT source and interval settings that best fit your infrastructure and performance needs.


Next Steps:

  • CLI Options: Full list of flags and environment variables.

Submitter Configuration

The Submitter node publishes PRISM DID operations to the Cardano blockchain.
It is typically used for creating, updating, or deactivating DIDs.

DLT Sink

The Submitter node currently supports Cardano wallet integration as its DLT sink:

  • Cardano Wallet:
    Uses a Cardano wallet to sign and submit transactions containing DID operations.
    • Key options:
      • Wallet base URL: --wallet-base-url or NPRISM_WALLET_BASE_URL
      • Wallet ID: --wallet-id or NPRISM_WALLET_ID
      • Passphrase: --wallet-passphrase or NPRISM_WALLET_PASSPHRASE
      • Payment address: --payment-address or NPRISM_PAYMENT_ADDRESS

Important: When the submitter publishes a DID operation, it creates a transaction from the configured wallet to the specified payment address.
Make sure you use your own payment address. Using an incorrect or third-party address may result in permanent loss of funds.

Configure the wallet integration to match your operational and security requirements.


Next Steps:

  • CLI Options: Full list of flags and environment variables.

Logging

NeoPRISM uses structured logging to help you diagnose issues and monitor node activity. Logging is powered by the tracing crate, and log verbosity is controlled via the standard RUST_LOG environment variable. By default, NeoPRISM outputs all logs to stdout.

Configuring Logging

To set the log level, set the RUST_LOG environment variable before starting NeoPRISM. For example:

RUST_LOG=info

Supported log levels (in increasing verbosity) are: error, warn, info, debug, and trace.

You can also filter logs by module. For example, to see only HTTP-related logs at debug level:

RUST_LOG=neoprism_node::http=debug

Multiple filters can be combined:

RUST_LOG=info,oura=warn,neoprism_node::http=trace,tower_http::trace=debug

About RUST_LOG

NeoPRISM uses the standard tracing environment variables to control log verbosity and filtering, including RUST_LOG. For more details on how RUST_LOG works and advanced usage, see the tracing-subscriber EnvFilter documentation.

PRISM Specification Tests

The prism-test suite provides conformance tests for PRISM node implementations. These tests help developers verify that their NeoPRISM or PRISM node changes adhere to the PRISM specification.

Overview

The tests are located in the tests/prism-test directory. They cover key PRISM features such as DID creation, update, deactivation, and storage operations, ensuring your node implementation behaves as expected.

Running the Tests

1. Start Required Services

Navigate to the docker/prism-test directory and start the required services using Docker Compose:

cd docker/prism-test
docker-compose up

Note:
If you are testing changes to a PRISM node implementation locally, you may need to adjust the compose.yml or docker-compose.yml file (depending on which is present in your project) to use your locally built Docker image instead of the default image.
For example, update the image: field or use the build: directive to point to your local source.

This will launch all necessary dependencies for the test suite.

2. Run the Test Suite

In a separate terminal, navigate to the tests/prism-test directory and run the tests using sbt:

cd tests/prism-test
sbt test

The test results will indicate whether your PRISM node implementation conforms to the specification.

Who Should Use These Tests?

  • NeoPRISM Developers: Use these tests when making changes to NeoPRISM to ensure continued compliance.
  • PRISM Node Developers: Run the suite to validate your node implementation against the PRISM specification.

Adding a New PRISM Node Implementation

To include a new PRISM node implementation in the test suite:

  1. Edit MainSpec.scala:
    Go to MainSpec.scala and add your new node to the test suite by providing the appropriate layer and configuration.

  2. Implement NodeClient Interface (if needed):
    If your node uses a different RPC or API, you may need to implement the NodeClient interface in NodeClient.scala to adapt the test suite to your node’s communication protocol.

This allows you to run the conformance tests against your custom PRISM node implementation and verify its compliance with the PRISM specification.

CLI Options

Commands

Usage: neoprism-node <COMMAND>

Commands:
  indexer           Start the node in indexer mode
  submitter         Start the node in submitter mode
  standalone        Start the node in standalone mode
  generate-openapi  Generate OpenAPI specification for the API
  help              Print this message or the help of the given subcommand(s)

Options:
  -h, --help     Print help
  -V, --version  Print version

Indexer options

Start the node in indexer mode

Usage: neoprism-node indexer [OPTIONS] --db-url <DB_URL>

Options:
      --address <ADDRESS>
          Node HTTP server binding address [env: NPRISM_ADDRESS=] [default: 0.0.0.0]
  -p, --port <PORT>
          Node HTTP server listening port [env: NPRISM_PORT=] [default: 8080]
      --assets-path <ASSETS_PATH>
          The directory containing the web UI assets (CSS, JavaScript files) [env: NPRISM_ASSETS_PATH=] [default: ./bin/neoprism-node/assets]
      --cors-enabled
          Enable permissive CORS (https://docs.rs/tower-http/latest/tower_http/cors/struct.CorsLayer.html#method.permissive) [env: NPRISM_CORS_ENABLED=]
      --db-url <DB_URL>
          Database URL (e.g. postgres://user:pass@host:5432/db) [env: NPRISM_DB_URL=]
      --skip-migration
          Skip database migration on node startup [env: NPRISM_SKIP_MIGRATION=]
      --cardano-network <CARDANO_NETWORK>
          The Cardano network the node is syncing from [env: NPRISM_CARDANO_NETWORK=] [default: mainnet] [possible values: mainnet, preprod, preview]
      --cardano-relay-addr <CARDANO_RELAY_ADDR>
          Address of the Cardano relay node to sync from. If provided, the node will sync events from the Cardano relay node. (e.g. backbone.mainnet.cardanofoundation.org:3001) [env: NPRISM_CARDANO_RELAY_ADDR=]
      --cardano-dbsync-url <CARDANO_DBSYNC_URL>
          DB-Sync url. If provided, the node will sync events from DB Sync. (e.g. postgres://user:pass@host:5432/db) [env: NPRISM_CARDANO_DBSYNC_URL=]
      --cardano-dbsync-poll-interval <CARDANO_DBSYNC_POLL_INTERVAL>
          Number of seconds to wait before polling DB Sync for the next update [env: NPRISM_CARDANO_DBSYNC_POLL_INTERVAL=] [default: 10]
      --index-interval <INDEX_INTERVAL>
          Number of seconds to wait before checking for unindexed operations [env: NPRISM_INDEX_INTERVAL=] [default: 10]
      --confirmation-blocks <CONFIRMATION_BLOCKS>
          Number of confirmation blocks to wait before considering the block valid [env: NPRISM_CONFIRMATION_BLOCKS=] [default: 112]
  -h, --help
          Print help

Submitter options

Start the node in submitter mode

Usage: neoprism-node submitter [OPTIONS] --db-url <DB_URL> --cardano-wallet-base-url <CARDANO_WALLET_BASE_URL> --cardano-wallet-wallet-id <CARDANO_WALLET_WALLET_ID> --cardano-wallet-passphrase <CARDANO_WALLET_PASSPHRASE> --cardano-wallet-payment-addr <CARDANO_WALLET_PAYMENT_ADDR>

Options:
      --address <ADDRESS>
          Node HTTP server binding address [env: NPRISM_ADDRESS=] [default: 0.0.0.0]
  -p, --port <PORT>
          Node HTTP server listening port [env: NPRISM_PORT=] [default: 8080]
      --assets-path <ASSETS_PATH>
          The directory containing the web UI assets (CSS, JavaScript files) [env: NPRISM_ASSETS_PATH=] [default: ./bin/neoprism-node/assets]
      --cors-enabled
          Enable permissive CORS (https://docs.rs/tower-http/latest/tower_http/cors/struct.CorsLayer.html#method.permissive) [env: NPRISM_CORS_ENABLED=]
      --db-url <DB_URL>
          Database URL (e.g. postgres://user:pass@host:5432/db) [env: NPRISM_DB_URL=]
      --skip-migration
          Skip database migration on node startup [env: NPRISM_SKIP_MIGRATION=]
      --cardano-wallet-base-url <CARDANO_WALLET_BASE_URL>
          Base url of cardano wallet [env: NPRISM_CARDANO_WALLET_BASE_URL=]
      --cardano-wallet-wallet-id <CARDANO_WALLET_WALLET_ID>
          Wallet ID to use for making transactions [env: NPRISM_CARDANO_WALLET_WALLET_ID=]
      --cardano-wallet-passphrase <CARDANO_WALLET_PASSPHRASE>
          Passphrase for the wallet [env: NPRISM_CARDANO_WALLET_PASSPHRASE=]
      --cardano-wallet-payment-addr <CARDANO_WALLET_PAYMENT_ADDR>
          Payment address for making transactions [env: NPRISM_CARDANO_WALLET_PAYMENT_ADDR=]
  -h, --help
          Print help

Standalone options

Start the node in standalone mode

Usage: neoprism-node standalone [OPTIONS] --db-url <DB_URL> --cardano-wallet-base-url <CARDANO_WALLET_BASE_URL> --cardano-wallet-wallet-id <CARDANO_WALLET_WALLET_ID> --cardano-wallet-passphrase <CARDANO_WALLET_PASSPHRASE> --cardano-wallet-payment-addr <CARDANO_WALLET_PAYMENT_ADDR>

Options:
      --address <ADDRESS>
          Node HTTP server binding address [env: NPRISM_ADDRESS=] [default: 0.0.0.0]
  -p, --port <PORT>
          Node HTTP server listening port [env: NPRISM_PORT=] [default: 8080]
      --assets-path <ASSETS_PATH>
          The directory containing the web UI assets (CSS, JavaScript files) [env: NPRISM_ASSETS_PATH=] [default: ./bin/neoprism-node/assets]
      --cors-enabled
          Enable permissive CORS (https://docs.rs/tower-http/latest/tower_http/cors/struct.CorsLayer.html#method.permissive) [env: NPRISM_CORS_ENABLED=]
      --db-url <DB_URL>
          Database URL (e.g. postgres://user:pass@host:5432/db) [env: NPRISM_DB_URL=]
      --skip-migration
          Skip database migration on node startup [env: NPRISM_SKIP_MIGRATION=]
      --cardano-network <CARDANO_NETWORK>
          The Cardano network the node is syncing from [env: NPRISM_CARDANO_NETWORK=] [default: mainnet] [possible values: mainnet, preprod, preview]
      --cardano-relay-addr <CARDANO_RELAY_ADDR>
          Address of the Cardano relay node to sync from. If provided, the node will sync events from the Cardano relay node. (e.g. backbone.mainnet.cardanofoundation.org:3001) [env: NPRISM_CARDANO_RELAY_ADDR=]
      --cardano-dbsync-url <CARDANO_DBSYNC_URL>
          DB-Sync url. If provided, the node will sync events from DB Sync. (e.g. postgres://user:pass@host:5432/db) [env: NPRISM_CARDANO_DBSYNC_URL=]
      --cardano-dbsync-poll-interval <CARDANO_DBSYNC_POLL_INTERVAL>
          Number of seconds to wait before polling DB Sync for the next update [env: NPRISM_CARDANO_DBSYNC_POLL_INTERVAL=] [default: 10]
      --index-interval <INDEX_INTERVAL>
          Number of seconds to wait before checking for unindexed operations [env: NPRISM_INDEX_INTERVAL=] [default: 10]
      --confirmation-blocks <CONFIRMATION_BLOCKS>
          Number of confirmation blocks to wait before considering the block valid [env: NPRISM_CONFIRMATION_BLOCKS=] [default: 112]
      --cardano-wallet-base-url <CARDANO_WALLET_BASE_URL>
          Base url of cardano wallet [env: NPRISM_CARDANO_WALLET_BASE_URL=]
      --cardano-wallet-wallet-id <CARDANO_WALLET_WALLET_ID>
          Wallet ID to use for making transactions [env: NPRISM_CARDANO_WALLET_WALLET_ID=]
      --cardano-wallet-passphrase <CARDANO_WALLET_PASSPHRASE>
          Passphrase for the wallet [env: NPRISM_CARDANO_WALLET_PASSPHRASE=]
      --cardano-wallet-payment-addr <CARDANO_WALLET_PAYMENT_ADDR>
          Payment address for making transactions [env: NPRISM_CARDANO_WALLET_PAYMENT_ADDR=]
  -h, --help
          Print help

Generate OpenAPI options

Generate OpenAPI specification for the API

Usage: neoprism-node generate-openapi [OPTIONS]

Options:
      --output <OUTPUT>  Output file for the OpenAPI spec (stdout if not provided)
  -h, --help             Print help

OpenAPI specification

openapi: 3.1.0
info:
  title: neoprism-node
  description: ""
  license:
    name: ""
  version: 0.4.0
servers:
  - url: http://localhost:8080
    description: Local
  - url: https://neoprism.patlo.dev
    description: Public - mainnet
  - url: https://neoprism-preprod.patlo.dev
    description: Public - preprod
paths:
  /1.0/identifiers/{did}:
    get:
      tags:
        - Indexer API
      summary: Universal Resolver driver endpoint for resolving DIDs, designed for use behind a Universal Resolver proxy.
      description: This endpoint implements the Universal Resolver driver interface. It is intended to be used as a backend for the Universal Resolver proxy, enabling DID resolution via the Universal Resolver ecosystem. The response format and behavior are compatible with Universal Resolver expectations.
      operationId: universal_resolver_did
      parameters:
        - name: did
          in: path
          description: The Decentralized Identifier (DID) to resolve using the Universal Resolver driver.
          required: true
          schema:
            $ref: '#/components/schemas/Did'
      responses:
        "200":
          description: Successfully resolved the DID. Returns the DID Resolution Result.
          content:
            application/did-resolution:
              schema:
                $ref: '#/components/schemas/ResolutionResult'
        "400":
          description: The provided DID is invalid.
          content:
            application/did-resolution:
              schema:
                $ref: '#/components/schemas/ResolutionResult'
        "404":
          description: The DID does not exist in the index.
          content:
            application/did-resolution:
              schema:
                $ref: '#/components/schemas/ResolutionResult'
        "410":
          description: The DID has been deactivated.
          content:
            application/did-resolution:
              schema:
                $ref: '#/components/schemas/ResolutionResult'
        "500":
          description: An unexpected error occurred during resolution.
          content:
            application/did-resolution:
              schema:
                $ref: '#/components/schemas/ResolutionResult'
  /api/_system/health:
    get:
      tags:
        - System API
      operationId: health
      responses:
        "200":
          description: Healthy
          content:
            text/plain:
              schema:
                type: string
              example: Ok
  /api/_system/metadata:
    get:
      tags:
        - System API
      operationId: app_meta
      responses:
        "200":
          description: Healthy
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AppMeta'
  /api/did-data/{did}:
    get:
      tags:
        - Indexer API
      summary: Returns the DIDData protobuf message for a given DID, encoded in hexadecimal.
      description: The returned data is a protobuf message compatible with the legacy prism-node implementation. The object is encoded in hexadecimal format. This endpoint is useful for testing and verifying compatibility with existing operations already anchored on the blockchain.
      operationId: did_data
      parameters:
        - name: did
          in: path
          description: The Decentralized Identifier (DID) for which to retrieve the DIDData protobuf message.
          required: true
          schema:
            $ref: '#/components/schemas/Did'
      responses:
        "200":
          description: Successfully retrieved the DIDData protobuf message, encoded as a hexadecimal string.
          content:
            text/plain:
              schema:
                type: string
        "400":
          description: The provided DID is invalid.
        "404":
          description: The DID does not exist in the index.
        "500":
          description: An unexpected error occurred while retrieving DIDData.
  /api/dids/{did}:
    get:
      tags:
        - Indexer API
      summary: Resolves a W3C Decentralized Identifier (DID) according to the DID Resolution specification.
      description: This endpoint is fully compliant with the W3C DID Resolution specification. It returns a DID Resolution Result object, including metadata and the resolved DID Document, following the standard resolution process.
      operationId: resolve_did
      parameters:
        - name: did
          in: path
          description: The Decentralized Identifier (DID) to resolve.
          required: true
          schema:
            $ref: '#/components/schemas/Did'
      responses:
        "200":
          description: Successfully resolved the DID. Returns the DID Resolution Result.
          content:
            application/did-resolution:
              schema:
                $ref: '#/components/schemas/ResolutionResult'
        "400":
          description: The provided DID is invalid.
          content:
            application/did-resolution:
              schema:
                $ref: '#/components/schemas/ResolutionResult'
        "404":
          description: The DID does not exist in the index.
          content:
            application/did-resolution:
              schema:
                $ref: '#/components/schemas/ResolutionResult'
        "410":
          description: The DID has been deactivated.
          content:
            application/did-resolution:
              schema:
                $ref: '#/components/schemas/ResolutionResult'
        "500":
          description: An unexpected error occurred during resolution.
          content:
            application/did-resolution:
              schema:
                $ref: '#/components/schemas/ResolutionResult'
  /api/indexer-stats:
    get:
      tags:
        - Indexer API
      summary: Retrieves statistics about the indexer's latest processed slot and block.
      operationId: indexer_stats
      responses:
        "200":
          description: Successfully retrieved indexer statistics, including the latest processed slot and block numbers.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/IndexerStats'
  /api/signed-operation-submissions:
    post:
      tags:
        - Submitter API
      operationId: submit_signed_operations
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SignedOperationSubmissionRequest'
        required: true
      responses:
        "200":
          description: Operations submitted successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SignedOperationSubmissionResponse'
components:
  schemas:
    AppMeta:
      type: object
      required:
        - version
        - mode
      properties:
        mode:
          $ref: '#/components/schemas/AppMetaRunMode'
        version:
          type: string
    AppMetaRunMode:
      type: string
      enum:
        - Indexer
        - Submitter
        - Standalone
    Base64UrlStrNoPad:
      type: string
      description: |-
        # Example
        ```
        use identus_apollo::base64::Base64UrlStrNoPad;

        let b = b"hello world";
        let b64 = Base64UrlStrNoPad::from(b);
        assert!(b64.to_string() == "aGVsbG8gd29ybGQ");
        ```
    BlockNo:
      type: integer
      format: int64
      example: 42
      minimum: 0
    Did:
      type: string
      example: did:example:123456789abcdefghi
    DidDocument:
      type: object
      required:
        - context
        - id
        - verificationMethod
      properties:
        assertionMethod:
          type:
            - array
            - "null"
          items:
            $ref: '#/components/schemas/VerificationMethodOrRef'
        authentication:
          type:
            - array
            - "null"
          items:
            $ref: '#/components/schemas/VerificationMethodOrRef'
        capabilityDelegation:
          type:
            - array
            - "null"
          items:
            $ref: '#/components/schemas/VerificationMethodOrRef'
        capabilityInvocation:
          type:
            - array
            - "null"
          items:
            $ref: '#/components/schemas/VerificationMethodOrRef'
        context:
          type: array
          items:
            type: string
        id:
          $ref: '#/components/schemas/Did'
        keyAgreement:
          type:
            - array
            - "null"
          items:
            $ref: '#/components/schemas/VerificationMethodOrRef'
        service:
          type:
            - array
            - "null"
          items:
            $ref: '#/components/schemas/Service'
        verificationMethod:
          type: array
          items:
            $ref: '#/components/schemas/VerificationMethod'
    DidDocumentMetadata:
      type: object
      properties:
        canonicalId:
          oneOf:
            - type: "null"
            - $ref: '#/components/schemas/Did'
        created:
          type:
            - string
            - "null"
          format: date-time
        deactivated:
          type:
            - boolean
            - "null"
        updated:
          type:
            - string
            - "null"
          format: date-time
        versionId:
          type:
            - string
            - "null"
    DidResolutionError:
      type: object
      required:
        - type
      properties:
        detail:
          type:
            - string
            - "null"
        title:
          type:
            - string
            - "null"
        type:
          $ref: '#/components/schemas/DidResolutionErrorCode'
    DidResolutionErrorCode:
      type: string
      enum:
        - https://www.w3.org/ns/did#INVALID_DID
        - https://www.w3.org/ns/did#INVALID_DID_DOCUMENT
        - https://www.w3.org/ns/did#NOT_FOUND
        - https://www.w3.org/ns/did#REPRESENTATION_NOT_SUPPORTED
        - https://www.w3.org/ns/did#INVALID_DID_URL
        - https://www.w3.org/ns/did#METHOD_NOT_SUPPORTED
        - https://www.w3.org/ns/did#INVALID_OPTIONS
        - https://www.w3.org/ns/did#INTERNAL_ERROR
        - https://w3id.org/security#INVALID_PUBLIC_KEY
        - https://w3id.org/security#INVALID_PUBLIC_KEY_LENGTH
        - https://w3id.org/security#INVALID_PUBLIC_KEY_TYPE
        - https://w3id.org/security#UNSUPPORTED_PUBLIC_KEY_TYPE
        - https://w3id.org/security#INVALID_VERIFICATION_METHOD_URL
        - https://w3id.org/security#INVALID_CONTROLLED_IDENTIFIER_DOCUMENT_ID
        - https://w3id.org/security#INVALID_CONTROLLED_IDENTIFIER_DOCUMENT
        - https://w3id.org/security#INVALID_VERIFICATION_METHOD
        - https://w3id.org/security#INVALID_RELATIONSHIP_FOR_VERIFICATION_METHOD
    DidResolutionMetadata:
      type: object
      properties:
        contentType:
          type:
            - string
            - "null"
        error:
          oneOf:
            - type: "null"
            - $ref: '#/components/schemas/DidResolutionError'
    IndexerStats:
      type: object
      properties:
        last_prism_block_number:
          oneOf:
            - type: "null"
            - $ref: '#/components/schemas/BlockNo'
        last_prism_slot_number:
          oneOf:
            - type: "null"
            - $ref: '#/components/schemas/SlotNo'
    Jwk:
      type: object
      required:
        - kty
        - crv
      properties:
        crv:
          type: string
        kty:
          type: string
        x:
          oneOf:
            - type: "null"
            - $ref: '#/components/schemas/Base64UrlStrNoPad'
        "y":
          oneOf:
            - type: "null"
            - $ref: '#/components/schemas/Base64UrlStrNoPad'
    ResolutionResult:
      type: object
      required:
        - didResolutionMetadata
        - didDocumentMetadata
      properties:
        didDocument:
          oneOf:
            - type: "null"
            - $ref: '#/components/schemas/DidDocument'
        didDocumentMetadata:
          $ref: '#/components/schemas/DidDocumentMetadata'
        didResolutionMetadata:
          $ref: '#/components/schemas/DidResolutionMetadata'
    Service:
      type: object
      required:
        - id
        - type
        - serviceEndpoint
      properties:
        id:
          type: string
        serviceEndpoint:
          $ref: '#/components/schemas/ServiceEndpoint'
        type:
          $ref: '#/components/schemas/ServiceType'
    ServiceEndpoint:
      oneOf:
        - $ref: '#/components/schemas/StringOrMap'
        - type: array
          items:
            $ref: '#/components/schemas/StringOrMap'
    ServiceType:
      oneOf:
        - type: string
        - type: array
          items:
            type: string
    SignedOperationSubmissionRequest:
      type: object
      required:
        - signed_operations
      properties:
        signed_operations:
          type: array
          items:
            $ref: '#/components/schemas/SignedPrismOperationHexStr'
    SignedOperationSubmissionResponse:
      type: object
      required:
        - tx_id
      properties:
        tx_id:
          $ref: '#/components/schemas/TxId'
    SignedPrismOperationHexStr:
      type: string
      description: A hexadecimal string representing a SignedPrismOperation
      example: 0a086d61737465722d30124630440220442eec28ec60464acd8df155e73f88a1c7faf4549975582ff0601449525aba31022019257250071818066b377b83a8b1765df1b7dc21d9bccfc7d5da036801d3ba0e1a420a400a3e123c0a086d61737465722d3010014a2e0a09736563703235366b3112210398e61c14328a6a844eec6dc084b825ae8525f10204e9244aaf61260bd221a457
    SlotNo:
      type: integer
      format: int64
      example: 8086
      minimum: 0
    StringOrMap:
      oneOf:
        - type: string
        - type: object
          additionalProperties: {}
          propertyNames:
            type: string
    TxId:
      type: string
      example: 5ab0cf7e4c7cd4b63ba84a4fe299409be12ba85607cb6d1a149e80bc2eac070d
    VerificationMethod:
      type: object
      required:
        - id
        - type
        - controller
      properties:
        controller:
          type: string
        id:
          type: string
        publicKeyJwk:
          oneOf:
            - type: "null"
            - $ref: '#/components/schemas/Jwk'
        type:
          type: string
    VerificationMethodOrRef:
      oneOf:
        - $ref: '#/components/schemas/VerificationMethod'
        - type: string