diff --git a/E2E/Package.swift b/E2E/Package.swift
new file mode 100644
index 00000000..db79c4b6
--- /dev/null
+++ b/E2E/Package.swift
@@ -0,0 +1,40 @@
+// swift-tools-version: 5.7
+// The swift-tools-version declares the minimum version of Swift required to build this package.
+
+import PackageDescription
+
+let package = Package(
+ name: "e2e",
+ platforms: [.iOS(.v15), .macOS(.v12)],
+ products: [
+ ],
+ dependencies: [
+ .package(url: "https://github.com/apple/swift-openapi-generator", .upToNextMinor(from: "0.3.4")),
+ .package(url: "https://github.com/apple/swift-openapi-runtime", .upToNextMinor(from: "0.3.6")),
+ .package(url: "https://github.com/apple/swift-openapi-urlsession", .upToNextMinor(from: "0.3.0")),
+ .package(url: "https://github.com/nschum/SwiftHamcrest", .upToNextMajor(from: "2.2.1")),
+ .package(path: "../")
+ ],
+ targets: [
+ .testTarget(
+ name: "e2e",
+ dependencies: [
+ .product(name: "PrismAgent", package: "atala-prism-wallet-sdk-swift"),
+ .product(name: "Domain", package: "atala-prism-wallet-sdk-swift"),
+ .product(name: "OpenAPIRuntime", package: "swift-openapi-runtime"),
+ .product(name: "OpenAPIURLSession", package: "swift-openapi-urlsession"),
+ .product(name: "SwiftHamcrest", package: "SwiftHamcrest")
+ ],
+ path: "e2eTests",
+ resources: [
+ .copy("Resources")
+ ],
+ plugins: [
+ .plugin(
+ name: "OpenAPIGenerator",
+ package: "swift-openapi-generator"
+ )
+ ]
+ )
+ ]
+)
diff --git a/E2E/e2eTests/.gitignore b/E2E/e2eTests/.gitignore
new file mode 100644
index 00000000..37e88c80
--- /dev/null
+++ b/E2E/e2eTests/.gitignore
@@ -0,0 +1,2 @@
+Target
+properties.plist
\ No newline at end of file
diff --git a/E2E/e2eTests/README.md b/E2E/e2eTests/README.md
new file mode 100644
index 00000000..4a718801
--- /dev/null
+++ b/E2E/e2eTests/README.md
@@ -0,0 +1,313 @@
+# Swift library test automation
+
+## Description
+
+Due the lack of BDD frameworks that allows swift libraries to be tested this framework was built using concepts of:
+
+- Cucumber
+- SerenityBDD
+
+## Getting started
+
+The lifecycle of the framework is based on XCTest lifecycle.
+
+The `TestFramework` provides a base configuration class named `TestConfiguration` which must be extended.
+
+For now, only `1` child class is supported and we'll refer to that class as `Configuration`.
+
+```swift
+class MyConfig: TestConfiguration {
+ // ...
+}
+```
+
+### Defining the actors
+
+To create the `actors`, in the `Configuration` file you should override the base class method `createActors()`
+
+```swift
+ override func createActors() async throws -> [Actor] {
+ let actor1 = Actor("Bob").whoCanUse(MyCustomAbility.self)
+ let actor2 = Actor("Alice").whoCanUse(OtherCustomAbility.self )
+ return [actor1, actor2]
+ }
+```
+
+### Defining parsers
+
+Parsers are a method that enable us to convert the data provided in step to parameterized arguments in steps
+
+To parameterize a step we use curly brackets and the type inside (`{type}`). For example: `{actor} counts to {int}`
+
+If no `type` is inside the curly brackets, the framework will use `string` as default.
+
+Parsers that are native to the framework:
+
+- String: converts the value to `string`
+- Int: converts the value to `int`
+- Actor: converts the value to an existing `actor`. Note: the actor must exist.
+
+To declare new parsers in the `Configuration` class you can add a new parser as the following example:
+
+```swift
+ @ParameterParser
+ var myCustomParser = { (data: String) in
+ return MyCustomType(data: data)
+ }
+```
+
+### Defining reporter
+
+In the `Configuration` file you have to setup the reporters you want.
+
+By default it's `JunitReporter`, `HtmlReporter` and `DotReporter`.
+
+Example:
+
+```swift
+ override func createReporters() async throws -> [Reporter] {
+ return [ConsoleReporter(), HtmlReporter()]
+ }
+```
+
+#### Available reporters:
+
+- ConsoleReporter: pretty print bdd in console
+- DotReporter: prints `.` for each action and in the end prints a summary
+- HtmlReporter: generates a HTML file. Note: for now it's only creating a .txt file
+- JunitReporter: generates a XML file in junit format
+
+### Defining the steps
+
+To create steps using the framework you should extend the `Steps` class and define the `Step` variables through annotation.
+
+Here's an example:
+
+```swift
+class MyCustomSteps: Steps {
+ @Step("The {actor} counts to {int}")
+ var theActorCountsToANumber = { (myActor: Actor, number: Int) in
+ <#code#>
+ }
+ // ...
+}
+```
+
+### Defining the feature
+
+Extends `Feature` class and override the `title` and optionally the `description`.
+
+```swift
+class MyFeature: Feature {
+ override func title() -> String {
+ "My custom feature"
+ }
+
+ override func description() -> String {
+ "My custom feature description"
+ }
+
+ // ...
+}
+```
+
+### Defining the scenario
+
+Inside the `Feature` we define the scenarios that will be executed.
+
+```swift
+class MyFeature: Feature {
+ // ...
+
+ func myTestCase() async throws {
+ currentScenario = Scenario("My custom scenario")
+ .given("Bob knows how to count")
+ .when("Bob counts to 10")
+ .then("The system should have waited at least 10 seconds")
+ }
+}
+```
+
+For now it's not possible to parameterize the scenarios.
+
+## Additional information
+
+### Defining the abilities
+
+Abilities are a concept inherited from `Serenity BDD`. This allows the `actors` to execute commands only if they have the ability to.
+
+#### Adding the ability to the actor
+
+You can add an ability to the `Actor` using the method `whoCanUse`
+
+```swift
+ let myActor = Actor("My Actor").whoCanUse(MyAbility.self)
+```
+
+or adding to an existing `Actor`:
+
+```swift
+ myActor.whoCanUse(MyAbility.self)
+```
+
+### Defining reporters
+
+#### Console reporter
+
+Prints in a readable way all the actions taken during the execution.
+
+#### Dot reporter
+
+Simple reporter that prints `.` for the actions taken during the test and prints the overall results.
+
+#### Junit reporter
+
+Generates the result in a `junit.xml` format. That can be used in CI/CD tools.
+
+The result is available in the path provided by `Configuration` method `targetDirectory`.
+
+#### HTML reporter
+
+Generates a readable report with the steps executed and its results.
+
+The result is available in the path provided by `Configuration` method `targetDirectory`.
+
+Note: For now it's a plain txt file.
+
+#### Creating a custom reporter
+
+To create a custom reporter you have to create the class and extend the `Reporter` base class and implement the protocol methods.
+
+```swift
+class MyCustomReporter: Reporter {
+ func beforeFeature(_ feature: Feature) async throws {
+ <#code#>
+ }
+
+ // ...
+}
+```
+
+And add the reporter to the reporters list.
+
+## Assertions
+
+### Hamcrest
+
+This framework enable the usage of `Hamcrest`.
+
+Usage:
+
+```swift
+import SwiftHamcrest
+
+class MySteps: Steps {
+ @Step("{actor} should see the calculator shows {int}")
+ var bobShouldSeeTheCalculatorShowsExpectedNumber = { (bob: Actor, expectedNumber: Int) in
+ assertThat(expectedNumber, equalTo(result))
+ }
+}
+```
+
+### Wait
+
+There's an assertion method to wait for an asynchronous verification. The method accepts an optional timeout (seconds) - default: 30.
+
+It expects a boolean response for the assertion result.
+
+Example:
+
+```swift
+func myTest() {
+ try await Wait.until(timeout: 60) {
+ let response = try await api.getSomething()
+ return response.data == "EXPECTED"
+ }
+}
+```
+
+## Full example
+
+```swift
+import Foundation
+import XCTest
+import SwiftHamcrest
+
+class MyTest: Feature {
+ override func title() -> String {
+ "My custom title"
+ }
+
+ override class func description() -> String {
+ "My custom title"
+ }
+
+ func testMyCustomScenario1() {
+ currentScenario = Scenario("My custom scenario")
+ .given("Bob has a calculator")
+ .when("Bob sums 1 + 1")
+ .then("Bob should see the calculator shows 2")
+ }
+
+ func testMyCustomScenario2() {
+ currentScenario = Scenario("My custom scenario")
+ .given("Bob has a calculator")
+ .when("Bob sums 1 + 2")
+ .then("Bob should see the calculator shows 2")
+ }
+}
+
+class MySteps: Steps {
+ static var result = 0
+
+ @Step("{actor} has a calculator")
+ var bobHasCalculator = { (bob: Actor) in
+
+ }
+
+ @Step("{actor} sums {int} + {int}")
+ var bobSumsOnePlusOne = { (bob: Actor, n1: Int, n2: Int) in
+ result = n1 + n2
+ }
+
+ @Step("{actor} should see the calculator shows {int}")
+ var bobShouldSeeTheCalculatorShowsExpectedNumber = { (bob: Actor, expectedNumber: Int) in
+ assertThat(expectedNumber, equalTo(result))
+ }
+}
+
+class MyConfig: TestConfiguration {
+ override class func createInstance() -> ITestConfiguration {
+ MyConfig()
+ }
+
+ override func createActors() async throws -> [Actor] {
+ let bob = Actor("Bob")
+ return [bob]
+ }
+
+ override func setUp() async throws {
+
+ }
+
+ override func tearDown() async throws {
+
+ }
+
+ override func targetDirectory() -> URL {
+ return URL(fileURLWithPath: #file)
+ .deletingLastPathComponent()
+ .deletingLastPathComponent()
+ .appendingPathComponent("Target")
+ }
+}
+```
+
+## Disclaimer
+
+The framework is still under development.
+
+## References
+
+- Cucumber - https://cucumber.io/docs/cucumber/
+- Serenity screenplay - https://serenity-bdd.github.io/docs/screenplay/screenplay_fundamentals
diff --git a/E2E/e2eTests/Resources/properties.plist.example.plist b/E2E/e2eTests/Resources/properties.plist.example.plist
new file mode 100644
index 00000000..8475f149
--- /dev/null
+++ b/E2E/e2eTests/Resources/properties.plist.example.plist
@@ -0,0 +1,18 @@
+
+
+
+
+ MEDIATOR_OOB_URL
+
+ PRISM_AGENT_URL
+
+ APIKEY
+
+ PUBLISHED_DID
+
+ JWT_SCHEMA_GUID
+
+ ANONCRED_DEFINITION_GUID
+
+
+
diff --git a/E2E/e2eTests/Source/Abilities/OpenEnterpriseAPI.swift b/E2E/e2eTests/Source/Abilities/OpenEnterpriseAPI.swift
new file mode 100644
index 00000000..6f4189e6
--- /dev/null
+++ b/E2E/e2eTests/Source/Abilities/OpenEnterpriseAPI.swift
@@ -0,0 +1,487 @@
+import Foundation
+import OpenAPIRuntime
+import OpenAPIURLSession
+import HTTPTypes
+
+class OpenEnterpriseAPI: Ability {
+ typealias AbilityInstanceType = API
+ private var api: AbilityInstanceType? = nil
+
+ let actor: Actor
+ let abilityName: String = "OEA API"
+
+ required init(_ actor: Actor) {
+ self.actor = actor
+ }
+
+ func instance() -> AbilityInstanceType {
+ return api!
+ }
+
+ func setUp(_ actor: Actor) async throws {
+ api = API(StepReporterMiddleware(actor.name))
+ }
+
+ func tearDown() async throws {
+ }
+
+ class API {
+ private var transport: URLSessionTransport? = nil
+ private var client: Client? = nil
+
+ init(_ middlewares: ClientMiddleware...) {
+ transport = URLSessionTransport()
+ client = Client(
+ serverURL: URL(string: Config.agentUrl)!,
+ configuration: .init(dateTranscoder: MyDateTranscoder()),
+ transport: transport!,
+ middlewares: [APITokenMiddleware(apikey: Config.apiKey)] + middlewares
+ )
+ }
+
+ func isDidPresent(_ did: String) async throws -> Bool {
+ if (did.isEmpty) {
+ return false
+ }
+
+ do {
+ _ = try await getDid(did)
+ return true
+ } catch {
+ return false
+ }
+ }
+
+ func getDid(_ did: String) async throws -> Components.Schemas.ManagedDID {
+ let response = try await client!.getDid_hyphen_registrarDidsDidref(.init(path: .init(didRef: did)))
+ switch(response) {
+ case .ok(let okResponse):
+ switch(okResponse.body) {
+ case .json(let body):
+ return body
+ }
+ default:
+ throw Error.WrongResponse
+ }
+ }
+
+ func createUnpublishedDid() async throws -> Components.Schemas.CreateManagedDIDResponse {
+ let createManagedDidRequest = Components.Schemas.CreateManagedDidRequest(
+ documentTemplate: .init(
+ publicKeys: .init(
+ arrayLiteral: .init(
+ id: "key-1",
+ purpose: .assertionMethod
+ )
+ ),
+ services: []
+ )
+ )
+
+ let response = try await client!.postDid_hyphen_registrarDids(body: .json(createManagedDidRequest))
+
+ switch(response) {
+ case .created(let createdResponse):
+ switch(createdResponse.body) {
+ case .json(let body):
+ return body
+ }
+ default:
+ throw Error.WrongResponse
+ }
+ }
+
+ func publishDid(_ longFormDid: String) async throws -> Components.Schemas.DIDOperationResponse {
+ let response = try await client!.postDid_hyphen_registrarDidsDidrefPublications(path: .init(didRef: longFormDid))
+ switch (response) {
+ case .accepted(let acceptedResponse):
+ switch(acceptedResponse.body) {
+ case .json(let body):
+ return body
+ }
+ default:
+ throw Error.WrongResponse
+ }
+ }
+
+ func isJwtSchemaGuidPresent(_ guid: String) async throws -> Bool {
+ if (guid.isEmpty) {
+ return false
+ }
+
+ do {
+ _ = try await getJwtSchema(guid)
+ return true
+ } catch {
+ return false
+ }
+ }
+
+ func getJwtSchema(_ guid: String) async throws -> Components.Schemas.CredentialSchemaResponse {
+ let response = try await client!.getSchemaById(path: .init(guid: guid))
+
+ switch(response) {
+ case .ok(let okResponse):
+ switch(okResponse.body) {
+ case .json(let body):
+ return body
+ }
+ default:
+ throw Error.WrongResponse
+ }
+ }
+
+ func createJwtSchema(author: String) async throws -> Components.Schemas.CredentialSchemaResponse {
+ let schemaName = "automation-jwt-schema-" + UUID().uuidString
+ var schema = try OpenAPIValueContainer()
+ schema.value = [
+ "$id": "https://example.com/\(schemaName)",
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "description": "Automation schema description",
+ "type": "object",
+ "properties": [
+ "automation-required": [
+ "type": "string"
+ ],
+ "automation-optional": [
+ "type": "string"
+ ]
+ ]
+ ]
+
+ let credentialSchemaInput = Components.Schemas.CredentialSchemaInput(
+ name: schemaName,
+ version: "0.0.1",
+ description: "Some description to automation generated schema",
+ _type: "https://w3c-ccg.github.io/vc-json-schemas/schema/2.0/schema.json",
+ schema: schema,
+ tags: ["automation"],
+ author: author
+ )
+
+ let response = try await client!.createSchema(body: .json(credentialSchemaInput))
+ switch (response) {
+ case .created(let createdResponse):
+ switch (createdResponse.body) {
+ case .json(let body):
+ return body
+ }
+ default:
+ throw Error.WrongResponse
+ }
+ }
+
+ func isAnoncredDefinitionPresent(_ anoncredDefinitionGuid: String) async throws -> Bool {
+ if (anoncredDefinitionGuid.isEmpty) {
+ return false
+ }
+
+ do {
+ _ = try await getAnoncredDefinition(anoncredDefinitionGuid)
+ return true
+ } catch {
+ return false
+ }
+ }
+
+ func getAnoncredDefinition(_ anoncredDefinitionGuid: String) async throws -> Components.Schemas.CredentialDefinitionResponse {
+ let response = try await client!.getCredentialDefinitionById(path: .init(guid: anoncredDefinitionGuid))
+
+ switch(response) {
+ case .ok(let okResponse):
+ switch(okResponse.body){
+ case .json(let body):
+ return body
+ }
+ default:
+ throw Error.WrongResponse
+ }
+ }
+
+ func createAnoncredSchema(_ issuerId: String) async throws -> Components.Schemas.CredentialSchemaResponse {
+ let schemaName = "automation-anoncred-schema-" + UUID().uuidString
+
+ var schema = try OpenAPIValueContainer()
+ schema.value = [
+ "name": "Automation Anoncred",
+ "version": "1.0",
+ "issuerId": issuerId,
+ "attrNames": [
+ "name",
+ "age"
+ ]
+ ]
+
+ let credentialSchemaInput = Components.Schemas.CredentialSchemaInput(
+ name: schemaName,
+ version: "2.0.0",
+ description: "Some description to automation generated schema",
+ _type: "AnoncredSchemaV1",
+ schema: schema,
+ tags: ["automation"],
+ author: issuerId
+ )
+
+ let response = try await client!.createSchema(body: .json(credentialSchemaInput))
+ switch (response) {
+ case .created(let createdResponse):
+ switch (createdResponse.body) {
+ case .json(let body):
+ return body
+ }
+ default:
+ throw Error.WrongResponse
+ }
+ }
+
+ func createAnoncredDefinition(_ issuerId: String, _ anoncredSchemaGuid: String) async throws -> Components.Schemas.CredentialDefinitionResponse {
+ let definitionName = "automation-anoncred-definition-" + UUID().uuidString
+ let anoncredDefinition = Components.Schemas.CredentialDefinitionInput.init(
+ name: definitionName,
+ description: "Test Automation Auto-Generated",
+ version: "1.0.0",
+ tag: "automation-test",
+ author: issuerId,
+ schemaId: "\(Config.agentUrl)/schema-registry/schemas/\(anoncredSchemaGuid)",
+ signatureType: "CL",
+ supportRevocation: true
+ )
+
+ let response = try await client!.createCredentialDefinition(body: .json(anoncredDefinition))
+ switch(response) {
+ case .created(let createdResponse):
+ switch(createdResponse.body) {
+ case .json(let body):
+ return body
+ }
+ default:
+ throw Error.WrongResponse
+ }
+ }
+
+ func getConnections() async throws -> Components.Schemas.ConnectionsPage {
+ let response = try await client!.getConnections(.init())
+
+ switch(response) {
+ case .ok(let okResponse):
+ switch(okResponse.body) {
+ case .json(let response):
+ return response
+ }
+ default:
+ throw Error.WrongResponse
+ }
+ }
+
+ func getConnection(_ connectionId: String) async throws -> Components.Schemas.Connection {
+ let response = try await client!.getConnection(path: .init(connectionId: connectionId))
+
+ switch(response) {
+ case .ok(let okResponse):
+ switch(okResponse.body) {
+ case .json(let response):
+ return response
+ }
+ default:
+ throw Error.WrongResponse
+ }
+ }
+
+ func createConnection() async throws -> Components.Schemas.Connection {
+ let body = Components.Schemas.CreateConnectionRequest(label: "Alice")
+ let response = try await client!.createConnection(.init(body: .json(body)))
+
+ switch(response) {
+ case .created(let okResponse):
+ switch(okResponse.body) {
+ case .json(let body):
+ return body
+ }
+ default:
+ throw Error.WrongResponse
+ }
+ }
+
+ func offerCredential(_ connectionId: String) async throws -> Components.Schemas.IssueCredentialRecord {
+ var claims: OpenAPIValueContainer = try OpenAPIValueContainer()
+ claims.value = [
+ "automation-required" : UUID().uuidString
+ ]
+
+ let body = Components.Schemas.CreateIssueCredentialRecordRequest(
+ schemaId: "\(Config.agentUrl)/schema-registry/schemas/\(Config.jwtSchemaGuid)",
+ claims: claims,
+ issuingDID: Config.publishedDid,
+ connectionId: connectionId
+ )
+
+ let response = try await client!.createCredentialOffer(body: .json(body))
+ switch(response) {
+ case .created(let createdResponse):
+ switch(createdResponse.body){
+ case .json(let body):
+ return body
+ }
+ default:
+ throw Error.WrongResponse
+ }
+ }
+
+ func offerAnonymousCredential(_ connectionId: String) async throws -> Components.Schemas.IssueCredentialRecord {
+ var claims: OpenAPIValueContainer = try OpenAPIValueContainer()
+ claims.value = [
+ "name" : "automation",
+ "age" : "99"
+ ]
+
+ let body = Components.Schemas.CreateIssueCredentialRecordRequest(
+ credentialDefinitionId: Config.anoncredDefinitionGuid,
+ credentialFormat: "AnonCreds",
+ claims: claims,
+ automaticIssuance: true,
+ issuingDID: Config.publishedDid,
+ connectionId: connectionId
+ )
+
+ let response = try await client!.createCredentialOffer(body: .json(body))
+ switch(response) {
+ case .created(let createdResponse):
+ switch(createdResponse.body){
+ case .json(let body):
+ return body
+ }
+ default:
+ throw Error.WrongResponse
+ }
+ }
+
+ func getCredentialRecord(_ recordId: String) async throws -> Components.Schemas.IssueCredentialRecord {
+ let response = try await client!.getCredentialRecord(path: .init(recordId: recordId))
+ switch(response){
+ case .ok(let okResponse):
+ switch(okResponse.body){
+ case .json(let body):
+ return body
+ }
+ default:
+ throw Error.WrongResponse
+ }
+ }
+
+ func requestPresentProof(_ connectionId: String) async throws -> Components.Schemas.PresentationStatus {
+ let options = Components.Schemas.Options(
+ challenge: UUID().uuidString,
+ domain: Config.agentUrl
+ )
+
+ let proof = Components.Schemas.ProofRequestAux(
+ schemaId: Config.jwtSchemaGuid,
+ trustIssuers: []
+ )
+
+ let body = Components.Schemas.RequestPresentationInput(
+ connectionId: connectionId,
+ options: options,
+ proofs: [proof],
+ credentialFormat: "JWT"
+ )
+
+ let response = try await client!.requestPresentation(body: .json(body))
+
+ switch(response){
+ case .created(let createdResponse):
+ switch(createdResponse.body){
+ case .json(let body):
+ return body
+ }
+ default:
+ throw Error.WrongResponse
+ }
+ }
+
+ func getPresentation(_ presentationId: String) async throws -> Components.Schemas.PresentationStatus {
+ let response = try await client!.getPresentation(path: .init(presentationId: presentationId))
+ switch(response){
+ case .ok(let okResponse):
+ switch(okResponse.body){
+ case .json(let body):
+ return body
+ }
+ default:
+ throw Error.WrongResponse
+ }
+ }
+
+ enum Error: Swift.Error, Equatable {
+ case WrongResponse
+ }
+ }
+}
+
+// https://github.com/apple/swift-openapi-generator/issues/84
+struct MyDateTranscoder: DateTranscoder {
+ private var dateFormatters: [DateFormatter] = []
+
+ func encode(_ date: Date) throws -> String {
+ return dateFormatters[0].string(from: date)
+ }
+
+ func decode(_ string: String) throws -> Date {
+ for formatter in dateFormatters {
+ if let result = formatter.date(from: string) {
+ return result
+ }
+ }
+ throw DecodingError.dataCorrupted(.init(
+ codingPath: [],
+ debugDescription: "Date string does not match any of the expected formats"))
+ }
+
+ init() {
+ let dateFormatter = DateFormatter()
+ dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSS'Z'"
+ dateFormatters.append(dateFormatter)
+ }
+}
+
+extension HTTPField.Name {
+ static let apikey = Self("apikey")!
+}
+
+struct APITokenMiddleware: ClientMiddleware {
+ let apikey: String
+
+ func intercept(
+ _ request: HTTPRequest,
+ body: HTTPBody?,
+ baseURL: URL,
+ operationID: String,
+ next: @Sendable (HTTPRequest, HTTPBody?, URL) async throws -> (HTTPResponse, HTTPBody?)
+ ) async throws -> (HTTPResponse, HTTPBody?) {
+ var request = request
+ request.headerFields[.apikey] = apikey
+ return try await next(request, body, baseURL)
+ }
+
+ init(apikey: String) {
+ self.apikey = apikey
+ }
+}
+
+struct StepReporterMiddleware: ClientMiddleware {
+ private var actor: String
+
+ init(_ actor: String) {
+ self.actor = actor
+ }
+
+ func intercept(
+ _ request: HTTPRequest,
+ body: HTTPBody?,
+ baseURL: URL,
+ operationID: String,
+ next: @Sendable (HTTPRequest, HTTPBody?, URL) async throws -> (HTTPResponse, HTTPBody?)
+ ) async throws -> (HTTPResponse, HTTPBody?) {
+ return try await next(request, body, baseURL)
+ }
+}
diff --git a/E2E/e2eTests/Source/Abilities/Sdk.swift b/E2E/e2eTests/Source/Abilities/Sdk.swift
new file mode 100644
index 00000000..89110cd3
--- /dev/null
+++ b/E2E/e2eTests/Source/Abilities/Sdk.swift
@@ -0,0 +1,221 @@
+import Foundation
+import PrismAgent
+import Builders
+import Combine
+import Domain
+import Pluto
+import Core
+
+class Sdk: Ability {
+ typealias AbilityInstanceType = Client
+ let actor: Actor
+ let abilityName: String = "Swift SDK"
+ private var client: Client? = nil
+
+ required init(_ actor: Actor) {
+ self.actor = actor
+ }
+
+ func instance() -> AbilityInstanceType {
+ return client!
+ }
+
+ func setUp(_ actor: Actor) async throws {
+ client = try await Client()
+ try await client!.initialize()
+ }
+
+ func tearDown() async throws {
+ try await client?.tearDown()
+ }
+
+ class Client {
+ var credentialOfferStack: [Message] = []
+ var issueCredentialStack: [Message] = []
+ var proofOfRequestStack: [Message] = []
+ var receivedMessages: [String] = []
+ var cancellables = Set()
+
+ let prismAgent: PrismAgent
+
+ init() async throws {
+ let mediatorDID = try await Client.getPrismMediatorDid()
+// let mediatorDID = try await Client.getRootsMediatorDid()
+
+ let apollo = ApolloBuilder().build()
+ let castor = CastorBuilder(apollo: apollo).build()
+ let pluto = PlutoBuilder(setup: .init(
+ coreDataSetup: .init(
+ modelPath: .storeName("PrismPluto"),
+ storeType: .memory
+ ),
+ keychain: KeychainMock()
+ )).build()
+ let pollux = PolluxBuilder(pluto: pluto).build()
+ let mercury = MercuryBuilder(
+ castor: castor,
+ secretsStream: Client.createSecretsStream(
+ keyRestoration: apollo,
+ pluto: pluto,
+ castor: castor
+ )
+ ).build()
+
+ PrismAgent.setupLogging(logLevels: [
+ .prismAgent: .warning
+ ])
+
+ prismAgent = PrismAgent(
+ apollo: apollo,
+ castor: castor,
+ pluto: pluto,
+ pollux: pollux,
+ mercury: mercury,
+ mediationHandler: BasicMediatorHandler(
+ mediatorDID: mediatorDID,
+ mercury: mercury,
+ store: BasicMediatorHandler.PlutoMediatorStoreImpl(pluto: pluto)
+ )
+ )
+ }
+
+ func initialize() async throws {
+ try await prismAgent.start()
+
+ prismAgent.handleReceivedMessagesEvents()
+ .sink(
+ receiveCompletion: { completion in
+ switch completion {
+ case .finished:
+ print("Publisher completed successfully.")
+ case .failure(let error):
+ print("Publisher failed with error: \(error)")
+ }
+ },
+ receiveValue: { message in
+ if (self.receivedMessages.contains(message.id)) {
+ return
+ }
+ self.receivedMessages.append(message.id)
+ switch(message.piuri) {
+ case ProtocolTypes.didcommOfferCredential3_0.rawValue:
+ self.credentialOfferStack.append(message)
+ case ProtocolTypes.didcommIssueCredential3_0.rawValue:
+ self.issueCredentialStack.append(message)
+ case ProtocolTypes.didcommRequestPresentation.rawValue:
+ self.proofOfRequestStack.append(message)
+ default:
+ break
+ }
+ }
+ )
+ .store(in: &cancellables)
+
+ prismAgent.startFetchingMessages()
+ }
+
+ func tearDown() async throws {
+ prismAgent.stopFetchingMessages()
+ try await prismAgent.stop()
+ }
+
+ static private func getPrismMediatorDid() async throws -> DID {
+ let url = URL(string: Config.mediatorOobUrl)!
+ let jsonData: [String: Any] = try await Api.get(from: url)
+ let did = (jsonData["from"] as? String)!
+ return try DID(string: did)
+ }
+
+ static private func getRootsMediatorDid() async throws -> DID {
+ let url = URL(string: Config.mediatorOobUrl)!
+ let invitationUrl: String = try await Api.get(from: url)
+ let base64data: String = String(invitationUrl.split(separator: "?_oob=").last!)
+ let decodedData = Data(base64Encoded: base64data)!
+ let json = try (JSONSerialization.jsonObject(with: decodedData, options: []) as? [String: Any])!
+ let from = (json["from"] as? String)!
+ return try DID(string: from)
+ }
+
+ private static func fromBase64(_ encoded: String) -> Data {
+ var encoded = encoded;
+ let remainder = encoded.count % 4
+ if remainder > 0 {
+ encoded = encoded.padding(
+ toLength: encoded.count + 4 - remainder,
+ withPad: "=", startingAt: 0);
+ }
+ return Data(base64Encoded: encoded)!
+ // return String(data: data, encoding: .utf8)!
+ }
+
+ static private func createSecretsStream(
+ keyRestoration: KeyRestoration,
+ pluto: Pluto,
+ castor: Castor
+ ) -> AnyPublisher<[Secret], Error> {
+ pluto.getAllPeerDIDs()
+ .first()
+ .flatMap { array in
+ Future {
+ try await array.asyncMap { did, privateKeys, _ in
+ let privateKeys = try await privateKeys.asyncMap {
+ try await keyRestoration.restorePrivateKey($0)
+ }
+ let secrets = try parsePrivateKeys(
+ did: did,
+ privateKeys: privateKeys,
+ castor: castor
+ )
+
+ return secrets
+ }
+ }
+ }
+ .map {
+ $0.compactMap {
+ $0
+ }.flatMap {
+ $0
+ } }
+ .eraseToAnyPublisher()
+ }
+
+ static private func parsePrivateKeys(
+ did: DID,
+ privateKeys: [PrivateKey],
+ castor: Castor
+ ) throws -> [Domain.Secret] {
+ return try privateKeys
+ .map { $0 as? (PrivateKey & ExportableKey) }
+ .compactMap { $0 }
+ .map { privateKey in
+ let ecnumbasis = try castor.getEcnumbasis(did: did, publicKey: privateKey.publicKey())
+ return (did, privateKey, ecnumbasis)
+ }
+ .map { did, privateKey, ecnumbasis in
+ try parseToSecret(
+ did: did,
+ privateKey: privateKey,
+ ecnumbasis: ecnumbasis
+ )
+ }
+ }
+
+ static private func parseToSecret(did: DID, privateKey: PrivateKey & ExportableKey, ecnumbasis: String) throws -> Domain.Secret {
+ let id = did.string + "#" + ecnumbasis
+ let jwk = privateKey.jwk
+ guard
+ let dataJson = try? JSONEncoder().encode(jwk),
+ let stringJson = String(data: dataJson, encoding: .utf8)
+ else {
+ throw CommonError.invalidCoding(message: "Could not encode privateKey.jwk")
+ }
+ return .init(
+ id: id,
+ type: .jsonWebKey2020,
+ secretMaterial: .jwk(value: stringJson)
+ )
+ }
+ }
+
+}
diff --git a/E2E/e2eTests/Source/Api.swift b/E2E/e2eTests/Source/Api.swift
new file mode 100644
index 00000000..770fc9fa
--- /dev/null
+++ b/E2E/e2eTests/Source/Api.swift
@@ -0,0 +1,21 @@
+import Foundation
+
+class Api {
+ static func get(from url: URL) async throws -> [String : Any] {
+ let session = URLSession.shared
+ let (data, _) = try await session.data(from: url)
+ let response = try (JSONSerialization.jsonObject(with: data, options: []) as? [String: Any])!
+ return response
+ }
+
+ static func get(from url: URL) async throws -> String {
+ let session = URLSession.shared
+ let (data, _) = try await session.data(from: url)
+ let response = String(bytes: data, encoding: String.Encoding.utf8)!
+ return response
+ }
+}
+
+enum ApiError: Error {
+ case failure(message: String)
+}
diff --git a/E2E/e2eTests/Source/Config.swift b/E2E/e2eTests/Source/Config.swift
new file mode 100644
index 00000000..3a99131c
--- /dev/null
+++ b/E2E/e2eTests/Source/Config.swift
@@ -0,0 +1,120 @@
+import Foundation
+
+/// Initializes CucumberLite configuration
+class Config: TestConfiguration {
+ static var mediatorOobUrl: String = ""
+ static var agentUrl: String = ""
+ static var publishedDid: String = ""
+ static var jwtSchemaGuid: String = ""
+ static var anoncredDefinitionGuid: String = ""
+ static var apiKey: String = ""
+
+ override class func createInstance() -> ITestConfiguration {
+ return Config()
+ }
+
+ override func targetDirectory() -> URL {
+ return URL(fileURLWithPath: #file)
+ .deletingLastPathComponent()
+ .deletingLastPathComponent()
+ .appendingPathComponent("Target")
+ }
+
+ override func createReporters() async throws -> [Reporter] {
+ return [ConsoleReporter(), JunitReporter(), HtmlReporter()]
+ }
+
+ override func createActors() async throws -> [Actor] {
+ let cloudAgent = Actor("Cloud Agent").whoCanUse(OpenEnterpriseAPI.self)
+ let edgeAgent = Actor("Edge Agent").whoCanUse(Sdk.self )
+ return [cloudAgent, edgeAgent]
+ }
+
+ override func setUp() async throws {
+ Config.mediatorOobUrl = environment["MEDIATOR_OOB_URL"]!
+ Config.agentUrl = environment["PRISM_AGENT_URL"]!
+ Config.publishedDid = environment["PUBLISHED_DID"] ?? ""
+ Config.jwtSchemaGuid = environment["JWT_SCHEMA_GUID"] ?? ""
+ Config.anoncredDefinitionGuid = environment["ANONCRED_DEFINITION_GUID"] ?? ""
+ Config.apiKey = environment["APIKEY"] ?? ""
+
+ try await checkPublishedDid()
+ try await checkJwtSchema()
+ try await checkAnoncredDefinition()
+
+ print("Mediator", Config.mediatorOobUrl)
+ print("Agent", Config.agentUrl)
+ print("DID", Config.publishedDid)
+ print("JWT Schema", Config.jwtSchemaGuid)
+ print("Anoncred Definition", Config.anoncredDefinitionGuid)
+ // TODO: Get SDK version
+ }
+
+ override func tearDown() async throws {
+ }
+
+ private func checkPublishedDid() async throws {
+ let api = OpenEnterpriseAPI.API()
+ let isPresent = try await api.isDidPresent(Config.publishedDid)
+ if (isPresent) {
+ return
+ }
+ print("DID [\(Config.publishedDid)] not found. Creating a new one.")
+
+ let unpublishedDid = try await api.createUnpublishedDid()
+ let publishedDid = try await api.publishDid(unpublishedDid.longFormDid)
+ let shortFormDid = publishedDid.scheduledOperation.didRef
+
+ try await Wait.until(timeout: 60) {
+ let did = try await api.getDid(shortFormDid)
+ return did.status == "PUBLISHED"
+ }
+
+ Config.publishedDid = shortFormDid
+ }
+
+ private func checkJwtSchema() async throws {
+ let api = OpenEnterpriseAPI.API()
+ let isPresent = try await api.isJwtSchemaGuidPresent(Config.jwtSchemaGuid)
+ if (isPresent) {
+ return
+ }
+ print("JWT schema [\(Config.jwtSchemaGuid)] not found. Creating a new one.")
+
+ let jwtSchema = try await api.createJwtSchema(author: Config.publishedDid)
+ Config.jwtSchemaGuid = jwtSchema.guid
+ }
+
+ private func checkAnoncredDefinition() async throws {
+ let api = OpenEnterpriseAPI.API()
+ let isPresent = try await api.isAnoncredDefinitionPresent(Config.anoncredDefinitionGuid)
+ if (isPresent) {
+ return
+ }
+ print("Anoncred Definition not found for [\(Config.anoncredDefinitionGuid)]. Creating a new one.")
+
+ let anoncredSchema = try await api.createAnoncredSchema(Config.publishedDid)
+ let anoncredDefinition = try await api.createAnoncredDefinition(Config.publishedDid, anoncredSchema.guid)
+ Config.anoncredDefinitionGuid = anoncredDefinition.guid
+ }
+
+ private func writeToGithubSummary(_ command: String) {
+ // if (ProcessInfo.processInfo.environment.keys.contains("CI")) {
+ let process = Process()
+ process.launchPath = "/bin/bash"
+ process.arguments = ["-c", command]
+
+ let pipe = Pipe()
+ process.standardOutput = pipe
+ process.launch()
+
+ let data = pipe.fileHandleForReading.readDataToEndOfFile()
+ if let output = String(data: data, encoding: .utf8) {
+ print("Command output:\n\(output)")
+ }
+ }
+}
+
+enum ConfigError: Error {
+ case PublishedDIDNotFound
+}
diff --git a/E2E/e2eTests/Source/Features/AnoncredFeature.swift b/E2E/e2eTests/Source/Features/AnoncredFeature.swift
new file mode 100644
index 00000000..33aedb58
--- /dev/null
+++ b/E2E/e2eTests/Source/Features/AnoncredFeature.swift
@@ -0,0 +1,23 @@
+import Foundation
+import XCTest
+
+class AnoncredFeature: Feature {
+ override func title() -> String {
+ "Receive anonymous credential"
+ }
+
+ override func description() -> String {
+ "The Edge Agent should be able to receive an anonymous credential from Cloud Agent"
+ }
+
+ func testReceiveOneAnoncred() async throws {
+ currentScenario = Scenario("Receive one anonymous credential")
+ .given("Cloud Agent is connected to Edge Agent")
+ .when("Cloud Agent offers an anonymous credential")
+ .then("Edge Agent should receive the credential")
+ .when("Edge Agent accepts the credential")
+ .when("Cloud Agent should see the credential was accepted")
+ .then("Edge Agent wait to receive 1 issued credentials")
+ .then("Edge Agent process 1 issued credentials")
+ }
+}
diff --git a/E2E/e2eTests/Source/Features/ConnectionFeature.swift b/E2E/e2eTests/Source/Features/ConnectionFeature.swift
new file mode 100644
index 00000000..cba37ac2
--- /dev/null
+++ b/E2E/e2eTests/Source/Features/ConnectionFeature.swift
@@ -0,0 +1,18 @@
+
+final class ConnectionFeature: Feature {
+ override func title() -> String {
+ "Create connection"
+ }
+
+ override func description() -> String {
+ "The Edge Agent should be able to create a connection to Open Enterprise Agent"
+ }
+
+ func testConnection() async throws {
+ currentScenario = Scenario("Create connection between Cloud and Edge agents")
+ .given("Cloud Agent has a connection invitation")
+ .given("Cloud Agent shares invitation to Edge Agent")
+ .when("Edge Agent connects through the invite")
+ .then("Cloud Agent should have the connection status updated to 'ConnectionResponseSent'")
+ }
+}
diff --git a/E2E/e2eTests/Source/Features/CredentialFeature.swift b/E2E/e2eTests/Source/Features/CredentialFeature.swift
new file mode 100644
index 00000000..55556cf9
--- /dev/null
+++ b/E2E/e2eTests/Source/Features/CredentialFeature.swift
@@ -0,0 +1,40 @@
+import XCTest
+
+final class CredentialTests: Feature {
+ override func title() -> String {
+ "Receive verifiable credential"
+ }
+
+ override func description() -> String {
+ "The Edge Agent should be able to receive a verifiable credential from Cloud Agent"
+ }
+
+ func testReceiveOneCredential() async throws {
+ currentScenario = Scenario("Receive one verifiable credential")
+ .given("Cloud Agent is connected to Edge Agent")
+ .when("Cloud Agent offers a credential")
+ .then("Edge Agent should receive the credential")
+ .when("Edge Agent accepts the credential")
+ .when("Cloud Agent should see the credential was accepted")
+ .then("Edge Agent wait to receive 1 issued credentials")
+ .then("Edge Agent process 1 issued credentials")
+ }
+
+ func testReceiveMultipleCredentialsSequentially() async throws {
+ currentScenario = Scenario("Receive multiple verifiable credentials sequentially")
+ .given("Cloud Agent is connected to Edge Agent")
+ .when("Edge Agent accepts 3 credential offer sequentially from Cloud Agent")
+ .then("Cloud Agent should see all credentials were accepted")
+ .and("Edge Agent wait to receive 3 issued credentials")
+ .and("Edge Agent process 3 issued credentials")
+ }
+
+ func testReceiveMultipleCredentialsAtOnce() async throws {
+ currentScenario = Scenario("Receive multiple verifiable credentials at once")
+ .given("Cloud Agent is connected to Edge Agent")
+ .when("Edge Agent accepts 3 credentials offer at once from Cloud Agent")
+ .then("Cloud Agent should see all credentials were accepted")
+ .and("Edge Agent wait to receive 3 issued credentials")
+ .and("Edge Agent process 3 issued credentials")
+ }
+}
diff --git a/E2E/e2eTests/Source/Features/ProofOfRequestFeature.swift b/E2E/e2eTests/Source/Features/ProofOfRequestFeature.swift
new file mode 100644
index 00000000..5b512f3d
--- /dev/null
+++ b/E2E/e2eTests/Source/Features/ProofOfRequestFeature.swift
@@ -0,0 +1,20 @@
+import XCTest
+
+final class ProofOfRequestFeature: Feature {
+ override func title() -> String {
+ "Provide proof of request"
+ }
+
+ override func description() -> String {
+ "The Edge Agent should provide proof to Cloud Agent"
+ }
+
+ func testRespondToProofOfRequest() async throws {
+ currentScenario = Scenario("Respond to request proof")
+ .given("Cloud Agent is connected to Edge Agent")
+ .and("Edge Agent has 1 credentials issued by Cloud Agent")
+ .when("Cloud Agent asks for present-proof")
+ .and("Edge Agent sends the present-proof")
+ .then("Cloud Agent should see the present-proof is verified")
+ }
+}
diff --git a/E2E/e2eTests/Source/KeychainMock.swift b/E2E/e2eTests/Source/KeychainMock.swift
new file mode 100644
index 00000000..4640ccf2
--- /dev/null
+++ b/E2E/e2eTests/Source/KeychainMock.swift
@@ -0,0 +1,28 @@
+import Domain
+import Foundation
+import Pluto
+
+class KeychainMock: KeychainStore, KeychainProvider {
+ var keys: [String: KeychainStorableKey] = [:]
+
+ func getKey(
+ service: String,
+ account: String,
+ tag: String?,
+ algorithm: KeychainStorableKeyProperties.KeyAlgorithm,
+ type: KeychainStorableKeyProperties.KeyType
+ ) throws -> Data {
+ guard let key = keys[service+account] else {
+ throw PlutoError.errorRetrivingKeyFromKeychainKeyNotFound(service: service, account: account, applicationLabel: tag)
+ }
+ return key.storableData
+ }
+
+ func addKey(
+ _ key: KeychainStorableKey,
+ service: String,
+ account: String
+ ) throws {
+ keys[service+account] = key
+ }
+}
diff --git a/E2E/e2eTests/Source/Steps/CloudAgentSteps.swift b/E2E/e2eTests/Source/Steps/CloudAgentSteps.swift
new file mode 100644
index 00000000..692d7c15
--- /dev/null
+++ b/E2E/e2eTests/Source/Steps/CloudAgentSteps.swift
@@ -0,0 +1,57 @@
+import Foundation
+
+class CloudAgentSteps: Steps {
+ @Step("{actor} offers an anonymous credential")
+ var cloudAgentOffersAnAnonymousCredential = { (cloudAgent: Actor) in
+ try await CloudAgentWorkflow.offersAnonymousCredential(cloudAgent: cloudAgent)
+ }
+
+ @Step("{actor} asks for present-proof")
+ var cloudAgentAsksForPresentProof = { (cloudAgent: Actor) in
+ try await CloudAgentWorkflow.asksForPresentProof(cloudAgent: cloudAgent)
+ }
+
+ @Step("{actor} should see the present-proof is verified")
+ var cloudAgentShouldSeeThePresentProofIsVerified = { (cloudAgent: Actor) in
+ try await CloudAgentWorkflow.verifyPresentProof(cloudAgent: cloudAgent, expectedState: .PresentationVerified)
+ }
+
+ @Step("{actor} offers a credential")
+ var cloudAgentOffersACredential = { (cloudAgent: Actor) in
+ try await CloudAgentWorkflow.offersACredential(cloudAgent: cloudAgent)
+ }
+
+ @Step("{actor} should see the credential was accepted")
+ var cloudAgentShouldSeeTheCredentialWasAccepted = { (cloudAgent: Actor) in
+ let recordId: String = try cloudAgent.recall(key: "recordId")
+ try await CloudAgentWorkflow.verifyCredentialState(cloudAgent: cloudAgent, recordId: recordId, expectedState: .CredentialSent)
+ }
+
+ @Step("{actor} should see all credentials were accepted")
+ var cloudAgentSeeAllCredentialsWereAccepted = { (cloudAgent: Actor) in
+ let recordIdList: [String] = try cloudAgent.recall(key: "recordIdList")
+ for recordId in recordIdList {
+ try await CloudAgentWorkflow.verifyCredentialState(cloudAgent: cloudAgent, recordId: recordId, expectedState: .CredentialSent)
+ }
+ }
+
+ @Step("{actor} is connected to {actor}")
+ var cloudAgentIsConnectedToEdgeAgent = { (cloudAgent: Actor, edgeAgent: Actor) in
+ try await CloudAgentWorkflow.isConnectedToEdgeAgent(cloudAgent: cloudAgent, edgeAgent: edgeAgent)
+ }
+
+ @Step("{actor} has a connection invitation")
+ var cloudAgentHasAConnectionInvitation = { (cloudAgent: Actor) in
+ try await CloudAgentWorkflow.hasAConnectionInvitation(cloudAgent: cloudAgent)
+ }
+
+ @Step("{actor} shares invitation to {actor}")
+ var cloudAgentSharesInvitationToEdgeAgent = { (cloudAgent: Actor, edgeAgent: Actor) in
+ try await CloudAgentWorkflow.sharesInvitationToEdgeAgent(cloudAgent: cloudAgent, edgeAgent: edgeAgent)
+ }
+
+ @Step("{actor} should have the connection status updated to '{}'")
+ var cloudAgentShouldHaveTheConnectionStatusUpdatedToConnectionResponseSent = { (cloudAgent: Actor, state: String) in
+ try await CloudAgentWorkflow.shouldHaveTheConnectionStatusUpdated(cloudAgent: cloudAgent, expectedState: .ConnectionResponseSent)
+ }
+}
diff --git a/E2E/e2eTests/Source/Steps/EdgeAgentSteps.swift b/E2E/e2eTests/Source/Steps/EdgeAgentSteps.swift
new file mode 100644
index 00000000..18476efb
--- /dev/null
+++ b/E2E/e2eTests/Source/Steps/EdgeAgentSteps.swift
@@ -0,0 +1,73 @@
+import Foundation
+
+enum Riri: Error {
+ case Riri(message: String)
+}
+class EdgeAgentSteps: Steps {
+ @Step("{actor} sends the present-proof")
+ var edgeAgentSendsThePresentProof = { (edgeAgent: Actor) in
+ try await EdgeAgentWorkflow.waitForProofRequest(edgeAgent: edgeAgent)
+ try await EdgeAgentWorkflow.presentProof(edgeAgent: edgeAgent)
+ }
+
+ @Step("{actor} has {int} credentials issued by {actor}")
+ var edgeAgentHasCredentialsIssuedByCloudAgent = { (edgeAgent: Actor, numberOfCredentials: Int, cloudAgent: Actor) in
+ try await EdgeAgentWorkflow.hasIssuedCredentials(edgeAgent: edgeAgent, numberOfCredentialsIssued: numberOfCredentials, cloudAgent: cloudAgent)
+ }
+
+ @Step("{actor} accepts {int} credential offer sequentially from {actor}")
+ var edgeAgentAcceptsCredentialsOfferSequentiallyFromCloudAgent = { (edgeAgent: Actor, numberOfCredentials: Int, cloudAgent: Actor) in
+// throw TestFramework.Failure.parameterTypeNotFound
+ var recordIdList: [String] = []
+ for _ in 0.. String {
+ fatalError("Set feature title")
+ }
+
+ func description() -> String {
+ return ""
+ }
+
+ /// our lifecycle starts after xctest is ending
+ override func tearDown() async throws {
+ try await run()
+ try await super.tearDown()
+ }
+
+ override class func tearDown() {
+ // signal end of feature
+ TestConfiguration.shared().endCurrentFeature()
+ }
+
+ func run() async throws {
+ // check if we have the scenario
+ if (currentScenario == nil) {
+ fatalError("""
+ To run the feature you have to setup the scenario for each test case.
+ Usage:
+ func testMyScenario() async throws {
+ scenario = Scenario("description")
+ .given // ...
+ }
+ """)
+ }
+
+ try await TestConfiguration.setUpInstance()
+ try await TestConfiguration.shared().run(self, currentScenario!)
+ }
+}
diff --git a/E2E/e2eTests/TestFramework/BDD/Scenario.swift b/E2E/e2eTests/TestFramework/BDD/Scenario.swift
new file mode 100644
index 00000000..de7925d6
--- /dev/null
+++ b/E2E/e2eTests/TestFramework/BDD/Scenario.swift
@@ -0,0 +1,63 @@
+import Foundation
+import XCTest
+
+class Scenario {
+ let id = UUID().uuidString
+ var title: String
+ var steps: [ConcreteStep] = []
+ var pass: Bool = false
+ var error: Error? = nil
+
+ private var lastContext: String = ""
+
+ init(_ title: String) {
+ self.title = title
+ }
+
+ func fail(file: StaticString?, line: UInt?, message: String) {
+ if (file != nil) {
+ XCTFail(message, file: file!, line: line!)
+ } else {
+ XCTFail(message)
+ }
+ }
+
+ private func addStep(_ step: String) {
+ let stepInstance = ConcreteStep()
+ stepInstance.context = lastContext
+ stepInstance.action = step
+ steps.append(stepInstance)
+ }
+
+ func given(_ step: String) -> Scenario {
+ lastContext = "Given"
+ addStep(step)
+ return self
+ }
+
+ func when(_ step: String) -> Scenario {
+ lastContext = "When"
+ addStep(step)
+ return self
+ }
+
+ func then(_ step: String) -> Scenario {
+ lastContext = "Then"
+ addStep(step)
+ return self
+ }
+
+ func but(_ step: String) -> Scenario {
+ lastContext = "But"
+ addStep(step)
+ return self
+ }
+
+ func and(_ step: String) -> Scenario {
+ if (lastContext.isEmpty) {
+ fatalError("Trying to add an [and] step without previous context.")
+ }
+ addStep(step)
+ return self
+ }
+}
diff --git a/E2E/e2eTests/TestFramework/BDD/Step.swift b/E2E/e2eTests/TestFramework/BDD/Step.swift
new file mode 100644
index 00000000..0640ff59
--- /dev/null
+++ b/E2E/e2eTests/TestFramework/BDD/Step.swift
@@ -0,0 +1,23 @@
+
+import Foundation
+
+@propertyWrapper
+class Step {
+ let file: StaticString
+ let line: UInt
+ var definition: String
+ var callback: (T) async throws -> ()
+ var wrappedValue: () async throws -> () {
+ get {
+ return {}
+ }
+ }
+
+ init(wrappedValue: @escaping (T) async throws -> (), _ definition: String, file: StaticString = #file, line: UInt = #line) {
+ self.file = file
+ self.line = line
+ self.callback = wrappedValue
+ self.definition = definition
+ StepRegistry.addStep(self)
+ }
+}
diff --git a/E2E/e2eTests/TestFramework/Configuration/ClassLocator.swift b/E2E/e2eTests/TestFramework/Configuration/ClassLocator.swift
new file mode 100644
index 00000000..d7de7941
--- /dev/null
+++ b/E2E/e2eTests/TestFramework/Configuration/ClassLocator.swift
@@ -0,0 +1,44 @@
+import Foundation
+
+class ClassLocator {
+ public static func allClasses() -> [AnyClass] {
+ let numberOfClasses = Int(objc_getClassList(nil, 0))
+ if numberOfClasses > 0 {
+ let classesPtr = UnsafeMutablePointer.allocate(capacity: numberOfClasses)
+ let autoreleasingClasses = AutoreleasingUnsafeMutablePointer(classesPtr)
+ let count = objc_getClassList(autoreleasingClasses, Int32(numberOfClasses))
+ assert(numberOfClasses == count)
+ defer { classesPtr.deallocate() }
+ let classes = (0 ..< numberOfClasses).map { classesPtr[$0] }
+ return classes
+ }
+ return []
+ }
+
+ public static func subclasses(of `class`: AnyClass) -> [AnyClass] {
+ return self.allClasses().filter {
+ var ancestor: AnyClass? = $0
+ while let type = ancestor {
+ if ObjectIdentifier(type) == ObjectIdentifier(`class`) { return true }
+ ancestor = class_getSuperclass(type)
+ }
+ return false
+ }
+ }
+
+ public static func classes(conformToProtocol `protocol`: Protocol) -> [AnyClass] {
+ let classes = self.allClasses().filter { aClass in
+ var subject: AnyClass? = aClass
+ while let aClass = subject {
+ if class_conformsToProtocol(aClass, `protocol`) { return true }
+ subject = class_getSuperclass(aClass)
+ }
+ return false
+ }
+ return classes
+ }
+
+ public static func classes(conformTo: T.Type) -> [AnyClass] {
+ return self.allClasses().filter { $0 is T }
+ }
+}
diff --git a/E2E/e2eTests/TestFramework/Configuration/ITestConfiguration.swift b/E2E/e2eTests/TestFramework/Configuration/ITestConfiguration.swift
new file mode 100644
index 00000000..e6a24554
--- /dev/null
+++ b/E2E/e2eTests/TestFramework/Configuration/ITestConfiguration.swift
@@ -0,0 +1,33 @@
+import Foundation
+
+protocol ITestConfiguration {
+ static var shared: () -> ITestConfiguration {get}
+ static func createInstance() -> ITestConfiguration
+
+ func run(_ feature: Feature, _ currentScenario: Scenario) async throws
+
+ /// setup
+ func setUp() async throws
+
+ /// teardown
+ func tearDown() async throws
+
+ /// phases
+ func beforeFeature(_ feature: Feature) async throws
+ func beforeScenario(_ scenario: Scenario) async throws
+ func beforeStep(_ step: ConcreteStep)
+ func afterStep(_ stepOutcome: StepOutcome)
+ func afterScenario(_ scenarioOutcome: ScenarioOutcome) async throws
+ func afterFeature(_ featureOutcome: FeatureOutcome) async throws
+ func afterFeatures(_ featuresOutcome: [FeatureOutcome]) async throws
+
+ func endCurrentFeature()
+ func end()
+
+ /// methods
+ func createActors() async throws -> [Actor]
+ func createReporters() async throws -> [Reporter]
+ func report(_ phase: Phase, _ object: Any)
+ func targetDirectory() -> URL
+
+}
diff --git a/E2E/e2eTests/TestFramework/Configuration/ParameterParser.swift b/E2E/e2eTests/TestFramework/Configuration/ParameterParser.swift
new file mode 100644
index 00000000..2554bfa3
--- /dev/null
+++ b/E2E/e2eTests/TestFramework/Configuration/ParameterParser.swift
@@ -0,0 +1,25 @@
+
+import Foundation
+
+@propertyWrapper
+struct ParameterParser {
+ var wrappedValue: (String) async throws -> T
+
+ init(wrappedValue: @escaping (String) async throws -> T) {
+ self.wrappedValue = wrappedValue
+ ParserRegistry.addParser(wrappedValue)
+ }
+}
+
+struct ParserRegistry {
+ static var annotatedMethods: [String: (String) async throws -> Any] = [:]
+
+ static func getParser(_ name: String) async throws -> (String) async throws -> T {
+ return ParserRegistry.annotatedMethods[name] as! (String) async throws -> T
+ }
+
+ static func addParser(_ callback: @escaping (String) async throws -> T) {
+ let type = String(describing: T.self).uppercased()
+ ParserRegistry.annotatedMethods[type] = callback
+ }
+}
diff --git a/E2E/e2eTests/TestFramework/Configuration/Phase.swift b/E2E/e2eTests/TestFramework/Configuration/Phase.swift
new file mode 100644
index 00000000..d99d6abd
--- /dev/null
+++ b/E2E/e2eTests/TestFramework/Configuration/Phase.swift
@@ -0,0 +1,12 @@
+import Foundation
+
+enum Phase {
+ case AFTER_FEATURES
+ case BEFORE_FEATURE
+ case AFTER_FEATURE
+ case BEFORE_SCENARIO
+ case AFTER_SCENARIO
+ case BEFORE_STEP
+ case AFTER_STEP
+ case ACTION
+}
diff --git a/E2E/e2eTests/TestFramework/Configuration/TestConfiguration.swift b/E2E/e2eTests/TestFramework/Configuration/TestConfiguration.swift
new file mode 100644
index 00000000..66af4708
--- /dev/null
+++ b/E2E/e2eTests/TestFramework/Configuration/TestConfiguration.swift
@@ -0,0 +1,320 @@
+import Foundation
+import XCTest
+import SwiftHamcrest
+
+class TestConfiguration: ITestConfiguration {
+ static var shared = { instance! }
+
+ let environment: [String: String] = { readEnvironmentVariables() }()
+
+ private static var instance: ITestConfiguration? = nil
+ private static var actors: [String: Actor] = [:]
+
+ private var assertionFailure: (String, StaticString, UInt)? = nil
+ private var reporters: [Reporter] = []
+
+ private var result: ResultOutcome = ResultOutcome()
+ private var features: [Feature.Type] = []
+ private var steps: [Steps] = []
+
+ private var currentFeatureOutcome: FeatureOutcome? = nil
+ private var currentScenario: Scenario? = nil
+
+ class func createInstance() -> ITestConfiguration {
+ fatalError("Configuration must implement createInstance method")
+ }
+
+ func targetDirectory() -> URL {
+ fatalError("Configuration must implement targetDirectory method")
+ }
+
+ func createActors() async throws -> [Actor] {
+ fatalError("Configuration must implement createActors method")
+ }
+
+ func setUp() async throws {
+ fatalError("Configuration must implement setUp method")
+ }
+
+ func tearDown() async throws {
+ fatalError("Configuration must implement tearDown method")
+ }
+
+ @MainActor
+ static func setUpInstance() async throws {
+ if (instance == nil) {
+ XCTestObservationCenter.shared.addTestObserver(TestObserver())
+ }
+ try await setUpConfigurationInstance()
+
+ }
+
+ /// Refresh for each feature
+ func tearDownInstance() async throws {
+ try await tearDownSteps()
+ try await tearDownActors()
+ try await tearDownConfigurationInstance()
+ }
+
+ func createReporters() async throws -> [Reporter] {
+ return [JunitReporter(), HtmlReporter(), DotReporter()]
+ }
+
+ /// Main function that runs feature, scenario and steps
+ func run(_ feature: Feature, _ scenario: Scenario) async throws {
+ currentScenario = scenario
+ try await beforeFeature(feature)
+ try await beforeScenario(scenario)
+ let scenarioOutcome = try await runSteps(scenario)
+ try await afterScenario(scenarioOutcome)
+ }
+
+ func beforeFeature(_ feature: Feature) async throws {
+ let type: Feature.Type = type(of: feature)
+
+ if (features.contains(where: { $0 == type })) {
+ return
+ }
+
+ features.append(type)
+ currentFeatureOutcome = FeatureOutcome(feature)
+ result.featuresOutcome.append(currentFeatureOutcome!)
+
+ report(.BEFORE_FEATURE, feature)
+ }
+
+ func beforeScenario(_ scenario: Scenario) async throws {
+ report(.BEFORE_SCENARIO, scenario)
+ }
+
+ func beforeStep(_ step: ConcreteStep) {
+ report(.BEFORE_STEP, step.action)
+ }
+
+ func runSteps(_ scenario: Scenario) async throws -> ScenarioOutcome {
+ let scenarioOutcome = ScenarioOutcome(scenario)
+
+ for step in scenario.steps {
+ let stepOutcome: StepOutcome
+ report(.BEFORE_STEP, step)
+
+ do {
+ try await StepRegistry.run(step)
+ if (assertionFailure != nil) {
+ let message = assertionFailure!.0
+ let file = assertionFailure!.1
+ let line = assertionFailure!.2
+ XCTFail(message, file: file, line: line)
+ throw Assertion.AssertionError(
+ message: message,
+ file: file,
+ line: line
+ )
+ }
+ stepOutcome = StepOutcome(step)
+ } catch {
+ stepOutcome = StepOutcome(step, error)
+ currentScenario!.fail(file: step.file, line: step.line, message: String(describing: error))
+ }
+
+ scenarioOutcome.steps.append(stepOutcome)
+ report(.AFTER_STEP, stepOutcome)
+ assertionFailure = nil
+
+ if (stepOutcome.error != nil) {
+ scenarioOutcome.failedStep = stepOutcome
+ break
+ }
+ }
+ return scenarioOutcome
+ }
+
+ func afterStep(_ stepOutcome: StepOutcome) {
+ report(.AFTER_STEP, stepOutcome.step.action)
+ }
+
+ func afterScenario(_ scenarioOutcome: ScenarioOutcome) async throws {
+ currentFeatureOutcome!.scenarios.append(scenarioOutcome)
+ if (scenarioOutcome.failedStep != nil) {
+ currentFeatureOutcome!.failedScenarios.append(scenarioOutcome)
+ }
+ report(.AFTER_SCENARIO, scenarioOutcome)
+ }
+
+ func afterFeature(_ featureOutcome: FeatureOutcome) async throws {
+ report(.AFTER_FEATURE, featureOutcome)
+ }
+
+ func afterFeatures(_ featuresOutcome: [FeatureOutcome]) async throws {
+ report(.AFTER_FEATURES, featuresOutcome)
+ }
+
+ private func unsafeSync(_ f: @escaping () async -> ()) {
+ let semaphore = DispatchSemaphore(value: 0)
+ Task.init {
+ await f()
+ semaphore.signal()
+ }
+ semaphore.wait()
+ }
+
+ func endCurrentFeature() {
+ unsafeSync {
+ try! await self.afterFeature(self.currentFeatureOutcome!)
+ }
+ }
+
+ func end() {
+ unsafeSync {
+ try! await self.afterFeatures(self.result.featuresOutcome)
+ try! await self.tearDownInstance()
+ }
+ // TODO: throw exception if it fails
+ }
+
+ func report(_ phase: Phase, _ object: Any) {
+ self.reporters.forEach { reporter in
+ unsafeSync {
+ switch(phase) {
+ case .BEFORE_FEATURE:
+ try! await reporter.beforeFeature(object as! Feature)
+ case .AFTER_FEATURE:
+ try! await reporter.afterFeature(object as! FeatureOutcome)
+ case .BEFORE_SCENARIO:
+ try! await reporter.beforeScenario(object as! Scenario)
+ case .AFTER_SCENARIO:
+ try! await reporter.afterScenario(object as! ScenarioOutcome)
+ case .BEFORE_STEP:
+ try! await reporter.beforeStep(object as! ConcreteStep)
+ case .AFTER_STEP:
+ try! await reporter.afterStep(object as! StepOutcome)
+ case .ACTION:
+ try! await reporter.action(object as! String)
+ case .AFTER_FEATURES:
+ try! await reporter.afterFeatures(object as! [FeatureOutcome])
+ }
+ }
+ }
+ }
+
+ private func setUpActors() async throws {
+ let actors = try await createActors()
+ for actor in actors {
+ TestConfiguration.actors[actor.name] = actor
+ try await actor.initialize()
+ }
+ }
+
+ private func tearDownActors() async throws {
+ for actor in TestConfiguration.actors.values {
+ try await actor.tearDown()
+ }
+ }
+
+ private func setUpSteps() async throws {
+ let subclasses = ClassLocator.subclasses(of: Steps.self)
+ for subclass in subclasses {
+ if (subclass != Steps.self) {
+ steps.append(try await (subclass as! Steps.Type).init())
+ }
+ }
+ }
+
+ private func tearDownSteps() async throws {
+ for step in steps {
+ try await step.tearDown()
+ }
+ }
+
+ private static func setUpConfigurationInstance() async throws {
+ if (self.instance != nil) {
+ return
+ }
+
+ let subclasses = ClassLocator.subclasses(of: TestConfiguration.self).filter { $0 != TestConfiguration.self }
+ if (subclasses.count == 0) {
+ fatalError("No configuration class found. Create a class that extends CucumberConfig class.")
+ }
+ if (subclasses.count > 1) {
+ fatalError("More than 1 configuration class found.")
+ }
+
+ let instanceType = (subclasses[0] as! ITestConfiguration.Type)
+
+ // force as own instance
+ let instance = instanceType.createInstance() as! TestConfiguration
+
+ try await instance.setUp()
+ try await instance.setUpReporters()
+ try await instance.setUpSteps()
+ try await instance.setUpActors()
+
+ /// setup hamcrest to update variable if failed
+ HamcrestReportFunction = { message, file, line in
+ instance.assertionFailure = (message, file, line)
+ }
+
+ self.instance = instance
+
+ let fileManager = FileManager.default
+ /// delete target folder
+ do {
+ try fileManager.removeItem(at: instance.targetDirectory())
+ } catch {
+ }
+ /// recreate it
+ do {
+ try fileManager.createDirectory(at: instance.targetDirectory(), withIntermediateDirectories: true, attributes: nil)
+ } catch {
+ }
+ }
+
+ private func setUpReporters() async throws {
+ reporters = try await createReporters()
+ }
+
+ private func tearDownConfigurationInstance() async throws {
+ try await tearDown()
+ }
+
+ private static func readEnvironmentVariables() -> [String: String] {
+ var environment: [String: String] = [:]
+ // load property file
+ if let path = Bundle.module.path(forResource: "properties", ofType: "plist", inDirectory: "Resources") {
+ if let data = try? Data(contentsOf: URL(fileURLWithPath: path)) {
+ if let dictionary = try? (PropertyListSerialization.propertyList(from: data, options: [], format: nil) as! [String: String]) {
+ dictionary.forEach {
+ environment[$0.key] = $0.value
+ }
+ }
+ }
+ }
+ // overrides if any environment variable is available
+ ProcessInfo.processInfo.environment.forEach {
+ environment[$0.key] = $0.value
+ }
+ return environment
+ }
+
+ /// Default parsers
+ @ParameterParser
+ var actorParser = { (actor: String) in
+ return actors[actor]!
+ }
+
+ @ParameterParser
+ var stringParser = { (string: String) in
+ return string
+ }
+
+ @ParameterParser
+ var intParser = { (int: String) in
+ return Int(int)!
+ }
+
+ enum Failure: Error {
+ case StepParameterDoesNotMatch(step: String, expected: String, actual: String)
+ case StepNotFound(step: String)
+ case ParameterTypeNotFound
+ }
+}
diff --git a/E2E/e2eTests/TestFramework/Outcome/FeatureOutcome.swift b/E2E/e2eTests/TestFramework/Outcome/FeatureOutcome.swift
new file mode 100644
index 00000000..6060d5a5
--- /dev/null
+++ b/E2E/e2eTests/TestFramework/Outcome/FeatureOutcome.swift
@@ -0,0 +1,11 @@
+import Foundation
+
+class FeatureOutcome {
+ let feature: Feature
+ var scenarios: [ScenarioOutcome] = []
+ var failedScenarios: [ScenarioOutcome] = []
+
+ init(_ feature: Feature) {
+ self.feature = feature
+ }
+}
diff --git a/E2E/e2eTests/TestFramework/Outcome/ResultOutcome.swift b/E2E/e2eTests/TestFramework/Outcome/ResultOutcome.swift
new file mode 100644
index 00000000..c7dbf6f9
--- /dev/null
+++ b/E2E/e2eTests/TestFramework/Outcome/ResultOutcome.swift
@@ -0,0 +1,5 @@
+import Foundation
+
+class ResultOutcome {
+ var featuresOutcome: [FeatureOutcome] = []
+}
diff --git a/E2E/e2eTests/TestFramework/Outcome/ScenarioOutcome.swift b/E2E/e2eTests/TestFramework/Outcome/ScenarioOutcome.swift
new file mode 100644
index 00000000..3e1aad55
--- /dev/null
+++ b/E2E/e2eTests/TestFramework/Outcome/ScenarioOutcome.swift
@@ -0,0 +1,11 @@
+import Foundation
+
+class ScenarioOutcome {
+ let scenario: Scenario
+ var steps: [StepOutcome] = []
+ var failedStep: StepOutcome? = nil
+
+ init(_ scenario: Scenario) {
+ self.scenario = scenario
+ }
+}
diff --git a/E2E/e2eTests/TestFramework/Outcome/StepOutcome.swift b/E2E/e2eTests/TestFramework/Outcome/StepOutcome.swift
new file mode 100644
index 00000000..cee4f7fb
--- /dev/null
+++ b/E2E/e2eTests/TestFramework/Outcome/StepOutcome.swift
@@ -0,0 +1,11 @@
+import Foundation
+
+class StepOutcome {
+ let step: ConcreteStep
+ var error: Error?
+
+ init(_ step: ConcreteStep, _ error: Error? = nil) {
+ self.step = step
+ self.error = error
+ }
+}
diff --git a/E2E/e2eTests/TestFramework/Report/ConsoleReporter.swift b/E2E/e2eTests/TestFramework/Report/ConsoleReporter.swift
new file mode 100644
index 00000000..1ac18fed
--- /dev/null
+++ b/E2E/e2eTests/TestFramework/Report/ConsoleReporter.swift
@@ -0,0 +1,45 @@
+import Foundation
+
+class ConsoleReporter: Reporter {
+ private let pass = "(✔)"
+ private let fail = "(✘)"
+
+ private var actions: [String] = []
+
+ func beforeFeature(_ feature: Feature) async throws {
+ print()
+ print("Feature:", feature.title())
+ }
+
+ func beforeScenario(_ scenario: Scenario) async throws {
+ print(" ", scenario.title)
+ }
+
+ func beforeStep(_ step: ConcreteStep) async throws {
+ }
+
+ func action(_ action: String) async throws {
+ actions.append(action)
+ }
+
+ func afterStep(_ stepOutcome: StepOutcome) async throws {
+ let result = stepOutcome.error != nil ? fail : pass
+ print(" ", result, stepOutcome.step.action)
+ actions.forEach { action in
+ print(" ", action)
+ }
+ actions = []
+ }
+
+ func afterScenario(_ scenarioOutcome: ScenarioOutcome) async throws {
+ let result = scenarioOutcome.failedStep != nil ? "FAIL" : "PASS"
+ print(" ", "Result:", result)
+ }
+
+ func afterFeature(_ featureOutcome: FeatureOutcome) async throws {
+ print()
+ }
+
+ func afterFeatures(_ featuresOutcome: [FeatureOutcome]) async throws {
+ }
+}
diff --git a/E2E/e2eTests/TestFramework/Report/DotReporter.swift b/E2E/e2eTests/TestFramework/Report/DotReporter.swift
new file mode 100644
index 00000000..9377c73b
--- /dev/null
+++ b/E2E/e2eTests/TestFramework/Report/DotReporter.swift
@@ -0,0 +1,52 @@
+import Foundation
+
+class DotReporter: Reporter {
+ private func printDot() {
+ print(".", terminator: "")
+ }
+ func beforeFeature(_ feature: Feature) async throws {
+ printDot()
+ }
+
+ func beforeScenario(_ scenario: Scenario) async throws {
+ printDot()
+ }
+
+ func beforeStep(_ step: ConcreteStep) async throws {
+ printDot()
+ }
+
+ func action(_ action: String) async throws {
+ printDot()
+ }
+
+ func afterStep(_ stepOutcome: StepOutcome) async throws {
+ printDot()
+ }
+
+ func afterScenario(_ scenarioOutcome: ScenarioOutcome) async throws {
+ print()
+ }
+
+ func afterFeature(_ featureOutcome: FeatureOutcome) async throws {
+ }
+
+ func afterFeatures(_ featuresOutcome: [FeatureOutcome]) async throws {
+ print("Executed", featuresOutcome.count, "features")
+ for featureOutcome in featuresOutcome {
+ print(" ", "Feature:", featureOutcome.feature.title())
+ for scenarioOutcome in featureOutcome.scenarios {
+ print(
+ " ",
+ scenarioOutcome.failedStep != nil ? "(fail)" : "(pass)",
+ scenarioOutcome.scenario.title
+ )
+ if (scenarioOutcome.failedStep != nil) {
+ let failedStep = scenarioOutcome.failedStep!
+ print(" ", failedStep.error!)
+ print(" at step: \"\(failedStep.step.action)\"")
+ }
+ }
+ }
+ }
+}
diff --git a/E2E/e2eTests/TestFramework/Report/HtmlReporter.swift b/E2E/e2eTests/TestFramework/Report/HtmlReporter.swift
new file mode 100644
index 00000000..59858847
--- /dev/null
+++ b/E2E/e2eTests/TestFramework/Report/HtmlReporter.swift
@@ -0,0 +1,88 @@
+import Foundation
+
+class HtmlReporter: Reporter {
+ private let pass = "(✔)"
+ private let fail = "(✘)"
+
+ private var currentFeature: Feature? = nil
+ private var currentScenario: Scenario? = nil
+ private var currentStep: ConcreteStep? = nil
+ private var currentId: String? = nil
+
+ private var actions: [String: [String]] = [:]
+
+ func beforeFeature(_ feature: Feature) async throws {
+ currentFeature = feature
+ }
+
+ func beforeScenario(_ scenario: Scenario) async throws {
+ currentScenario = scenario
+ }
+
+ func beforeStep(_ step: ConcreteStep) async throws {
+ currentStep = step
+ currentId = currentFeature!.id + currentScenario!.id + step.id
+ }
+
+ func action(_ action: String) async throws {
+ if (actions[currentId!] == nil) {
+ actions[currentId!] = []
+ }
+ actions[currentId!]!.append(action)
+ }
+
+ func afterStep(_ stepOutcome: StepOutcome) async throws {
+ currentStep = nil
+ }
+
+ func afterScenario(_ scenarioOutcome: ScenarioOutcome) async throws {
+ currentScenario = nil
+ }
+
+ func afterFeature(_ featureOutcome: FeatureOutcome) async throws {
+ currentFeature = nil
+ }
+
+ func afterFeatures(_ featuresOutcome: [FeatureOutcome]) async throws {
+
+ var summary = ""
+ summary.append("Executed \(featuresOutcome.count) features\n")
+
+ for featureOutcome in featuresOutcome {
+ summary.append(" Feature: \(featureOutcome.feature.title())\n")
+
+ for scenarioOutcome in featureOutcome.scenarios {
+ summary.append(" Scenario: \(scenarioOutcome.scenario.title)\n")
+
+ for stepOutcome in scenarioOutcome.steps {
+ if (stepOutcome.error != nil) {
+ summary.append(" \(fail) \(stepOutcome.step.action)\n")
+ } else {
+ summary.append(" \(pass) \(stepOutcome.step.action)\n")
+ }
+ let stepId = featureOutcome.feature.id + scenarioOutcome.scenario.id + stepOutcome.step.id
+ if let stepActions = actions[stepId] {
+ for action in stepActions {
+ summary.append(" \(action)\n")
+ }
+ }
+ if (stepOutcome.error != nil) {
+ summary.append(" caused by: \(String(describing: scenarioOutcome.failedStep!.error!))\n")
+ }
+ }
+
+ if (scenarioOutcome.failedStep != nil) {
+ summary.append(" Status: FAILED\n")
+ } else {
+ summary.append(" Status: SUCCESS\n")
+ }
+
+ summary.append("\n")
+
+ }
+ }
+
+ let outputPath = TestConfiguration.shared().targetDirectory().appendingPathComponent("result.txt")
+ try summary.write(to: outputPath, atomically: true, encoding: .utf8)
+ }
+}
diff --git a/E2E/e2eTests/TestFramework/Report/JunitReporter.swift b/E2E/e2eTests/TestFramework/Report/JunitReporter.swift
new file mode 100644
index 00000000..492cfd18
--- /dev/null
+++ b/E2E/e2eTests/TestFramework/Report/JunitReporter.swift
@@ -0,0 +1,121 @@
+import Foundation
+
+class JunitReporter: Reporter {
+ let root = XMLElement(name: "testsuites")
+ let xml: XMLDocument
+
+ var currentFeature = XMLElement(name: "testsuite")
+ var currentScenario = XMLElement(name: "testcase")
+
+ let testSuitesStart = Date()
+ var featureStart = Date()
+ var scenarioStart = Date()
+
+ var totalTests: Int = 0
+ var totalFailures: Int = 0
+ var featureTests: Int = 0
+ var featureFailures: Int = 0
+
+ init() {
+ xml = XMLDocument(rootElement: root)
+ xml.version = "1.0"
+ xml.characterEncoding = "UTF-8"
+
+ let dateFormatter = DateFormatter()
+ dateFormatter.dateFormat = "yyyyMMdd_HHmmss"
+
+ let currentDate = Date()
+ let formattedDate = dateFormatter.string(from: currentDate)
+
+ let id = XMLNode.attribute(withName: "id", stringValue: formattedDate) as! XMLNode
+ let name = XMLNode.attribute(withName: "name", stringValue: "swift-e2e-results - \(Date().formatted())") as! XMLNode
+
+ root.addAttribute(id)
+ root.addAttribute(name)
+ }
+
+ func beforeFeature(_ feature: Feature) async throws {
+ featureStart = Date()
+ currentFeature = XMLElement(name: "testsuite")
+ featureTests = 0
+ featureFailures = 0
+
+ let id = XMLNode.attribute(withName: "id", stringValue: feature.id) as! XMLNode
+ let name = XMLNode.attribute(withName: "name", stringValue: feature.title()) as! XMLNode
+
+ currentFeature.addAttribute(id)
+ currentFeature.addAttribute(name)
+
+ root.addChild(currentFeature)
+ }
+
+ func beforeScenario(_ scenario: Scenario) async throws {
+ scenarioStart = Date()
+ currentScenario = XMLElement(name: "testcase")
+
+ let id = XMLNode.attribute(withName: "id", stringValue: scenario.id) as! XMLNode
+ let name = XMLNode.attribute(withName: "name", stringValue: scenario.title) as! XMLNode
+
+ currentScenario.addAttribute(id)
+ currentScenario.addAttribute(name)
+
+ currentFeature.addChild(currentScenario)
+ }
+
+ func beforeStep(_ step: ConcreteStep) async throws {
+ }
+
+ func action(_ action: String) async throws {
+ }
+
+ func afterStep(_ stepOutcome: StepOutcome) async throws {
+ }
+
+ func afterScenario(_ scenarioOutcome: ScenarioOutcome) async throws {
+ featureTests += 1
+ let delta = String(format: "%.4f seconds", Date().timeIntervalSince(scenarioStart))
+ let time = XMLNode.attribute(withName: "time", stringValue: delta) as! XMLNode
+ currentScenario.addAttribute(time)
+
+ if (scenarioOutcome.failedStep != nil) {
+ let failure = XMLElement(name: "failure")
+ featureFailures += 1
+ let message = XMLNode.attribute(withName: "message", stringValue: String(describing: scenarioOutcome.failedStep!.error!)) as! XMLNode
+ let type = XMLNode.attribute(withName: "type", stringValue: "ERROR") as! XMLNode
+ failure.addAttribute(message)
+ failure.addAttribute(type)
+
+ currentScenario.addChild(failure)
+ }
+ }
+
+ func afterFeature(_ featureOutcome: FeatureOutcome) async throws {
+ let delta = String(format: "%.4f seconds", Date().timeIntervalSince(featureStart))
+ let time = XMLNode.attribute(withName: "time", stringValue: delta) as! XMLNode
+ let tests = XMLNode.attribute(withName: "tests", stringValue: String(featureTests)) as! XMLNode
+ let failures = XMLNode.attribute(withName: "failures", stringValue: String(featureFailures)) as! XMLNode
+ currentFeature.addAttribute(time)
+ currentFeature.addAttribute(tests)
+ currentFeature.addAttribute(failures)
+
+ totalTests += featureTests
+ totalFailures += featureFailures
+ }
+
+ func afterFeatures(_ featuresOutcome: [FeatureOutcome]) async throws {
+ let delta = String(format: "%.4f seconds", Date().timeIntervalSince(testSuitesStart))
+ let time = XMLNode.attribute(withName: "time", stringValue: delta) as! XMLNode
+ let tests = XMLNode.attribute(withName: "tests", stringValue: String(totalTests)) as! XMLNode
+ let failures = XMLNode.attribute(withName: "failures", stringValue: String(totalFailures)) as! XMLNode
+
+ root.addAttribute(time)
+ root.addAttribute(tests)
+ root.addAttribute(failures)
+
+ let outputPath = TestConfiguration.shared().targetDirectory().appendingPathComponent("junit.xml")
+ let prettyPrintOptions: XMLNode.Options = [.nodePrettyPrint]
+ let prettyPrintedData = xml.xmlData(options: prettyPrintOptions)
+ let summary = String(data: prettyPrintedData, encoding: .utf8)
+ try summary!.write(to: outputPath, atomically: true, encoding: .utf8)
+ }
+}
diff --git a/E2E/e2eTests/TestFramework/Report/Reporter.swift b/E2E/e2eTests/TestFramework/Report/Reporter.swift
new file mode 100644
index 00000000..6e0b5930
--- /dev/null
+++ b/E2E/e2eTests/TestFramework/Report/Reporter.swift
@@ -0,0 +1,12 @@
+import Foundation
+
+protocol Reporter {
+ func beforeFeature(_ feature: Feature) async throws
+ func beforeScenario(_ scenario: Scenario) async throws
+ func beforeStep(_ step: ConcreteStep) async throws
+ func action(_ action: String) async throws
+ func afterStep(_ stepOutcome: StepOutcome) async throws
+ func afterScenario(_ scenarioOutcome: ScenarioOutcome) async throws
+ func afterFeature(_ featureOutcome: FeatureOutcome) async throws
+ func afterFeatures(_ featuresOutcome: [FeatureOutcome]) async throws
+}
diff --git a/E2E/e2eTests/TestFramework/Report/TestObserver.swift b/E2E/e2eTests/TestFramework/Report/TestObserver.swift
new file mode 100644
index 00000000..3edf2f51
--- /dev/null
+++ b/E2E/e2eTests/TestFramework/Report/TestObserver.swift
@@ -0,0 +1,8 @@
+import Foundation
+import XCTest
+
+class TestObserver: NSObject, XCTestObservation {
+ func testBundleDidFinish(_ testBundle: Bundle) {
+ TestConfiguration.shared().end()
+ }
+}
diff --git a/E2E/e2eTests/TestFramework/Runner/ConcreteStep.swift b/E2E/e2eTests/TestFramework/Runner/ConcreteStep.swift
new file mode 100644
index 00000000..3a0a57a3
--- /dev/null
+++ b/E2E/e2eTests/TestFramework/Runner/ConcreteStep.swift
@@ -0,0 +1,20 @@
+import Foundation
+
+/**
+ Concrete step
+ */
+class ConcreteStep {
+ let id: String
+ var context: String = ""
+ var action: String = ""
+ var line: UInt? = nil
+ var file: StaticString? = nil
+
+ init() {
+ id = UUID().uuidString
+ }
+
+ static func == (lhs: ConcreteStep, rhs: ConcreteStep) -> Bool {
+ return lhs.context == rhs.context && lhs.action == rhs.action
+ }
+}
diff --git a/E2E/e2eTests/TestFramework/Runner/StepRegistry.swift b/E2E/e2eTests/TestFramework/Runner/StepRegistry.swift
new file mode 100644
index 00000000..57eef102
--- /dev/null
+++ b/E2E/e2eTests/TestFramework/Runner/StepRegistry.swift
@@ -0,0 +1,82 @@
+import Foundation
+
+struct StepRegistry {
+
+ static var runnableSteps: [String : StepRunner] = [:]
+
+ static func run(_ concreteStep: ConcreteStep) async throws {
+ let action = concreteStep.action
+ var parameters: [String] = []
+ var matchedStep: String?
+
+ for stepMatcher in runnableSteps.keys {
+ if let regex = try? NSRegularExpression(pattern: stepMatcher, options: []) {
+ let range = NSRange(action.startIndex..., in: action)
+ regex.enumerateMatches(in: action, options: [], range: range) { (match, _, _) in
+ if let match = match {
+ matchedStep = stepMatcher
+ for i in 1..(_ step: Step) {
+ let runnableStep = StepRunner(step)
+ runnableSteps[runnableStep.stepMatcher] = runnableStep
+ }
+}
diff --git a/E2E/e2eTests/TestFramework/Runner/StepRunner.swift b/E2E/e2eTests/TestFramework/Runner/StepRunner.swift
new file mode 100644
index 00000000..eb0dc2b4
--- /dev/null
+++ b/E2E/e2eTests/TestFramework/Runner/StepRunner.swift
@@ -0,0 +1,87 @@
+import Foundation
+
+class StepRunner {
+ private let callback: (Any) async throws -> ()
+ let stepDefinition: String
+ var stepMatcher: String
+ var parsers: [(String) async throws -> Any]
+ var stepLine: UInt
+ var stepFile: StaticString
+ private static var parameterPattern = "\\{([^}]*)\\}"
+ private static var specialCharacters = [".", "*", "+", "?", "^", "$", "[", "]", "|", "(", ")", "\\"]
+
+ init(_ step: Step) {
+ self.stepLine = step.line
+ self.stepFile = step.file
+ self.stepDefinition = step.definition
+
+ self.callback = { input in
+ guard let typedInput = input as? T else {
+ let mirror = Mirror(reflecting: input)
+ let actualType: String =
+ if (String(describing: mirror.displayStyle!) == "tuple") {
+ "(" + mirror.children.map { String(describing: type(of: $0.value)) }.joined(separator: ", ") + ")"
+ } else {
+ String(describing: mirror.subjectType)
+ }
+
+ throw TestConfiguration.Failure.StepParameterDoesNotMatch(
+ step: step.definition,
+ expected: String(describing: T.self),
+ actual: String(describing: actualType)
+ )
+ }
+ return try await step.callback(typedInput)
+ }
+ self.stepMatcher = StepRunner.createMatcher(stepDefinition)
+ self.parsers = StepRunner.createParsers(stepDefinition)
+ }
+
+ private static func createMatcher(_ stepDefinition: String) -> String {
+ let sanitizedString = sanitizeString(stepDefinition)
+ return sanitizedString.replacingOccurrences(of: StepRunner.parameterPattern, with: "(.*)", options: .regularExpression)
+ }
+
+ private static func sanitizeString(_ stepDefinition: String) -> String {
+ return stepDefinition.map { char -> String in
+ if specialCharacters.contains(String(char)) {
+ return "\\" + String(char)
+ } else {
+ return String(char)
+ }
+ }.joined()
+ }
+
+ private static func createParsers(_ stepDefinition: String) -> [(String) async throws -> Any] {
+ var parsers: [(String) async throws -> Any] = []
+ for parser in getStepParameterTypes(from: stepDefinition) {
+ let method = ParserRegistry.annotatedMethods[parser.uppercased()]!
+ parsers.append(method)
+ }
+ return parsers
+ }
+
+ private static func getStepParameterTypes(from text: String) -> [String] {
+ do {
+ let regex = try NSRegularExpression(pattern: StepRunner.parameterPattern, options: [])
+ let nsString = NSString(string: text)
+ let matches = regex.matches(in: text, options: [], range: NSRange(location: 0, length: nsString.length))
+
+ return matches.map { match in
+ let range = match.range(at: 1)
+ if range.location != NSNotFound {
+ let parser = nsString.substring(with: range)
+ return parser.isEmpty ? "string" : parser
+ } else {
+ return "string"
+ }
+ }
+ } catch {
+ fatalError("Unable to get parameters type")
+ }
+ }
+
+ func invoke(parameters: T) async throws {
+ try await callback(parameters)
+ }
+}
diff --git a/E2E/e2eTests/TestFramework/Runner/Steps.swift b/E2E/e2eTests/TestFramework/Runner/Steps.swift
new file mode 100644
index 00000000..ac22e247
--- /dev/null
+++ b/E2E/e2eTests/TestFramework/Runner/Steps.swift
@@ -0,0 +1,12 @@
+import Foundation
+
+class Steps {
+ required init() async throws {
+ }
+
+ func setUp() async throws {
+ }
+
+ func tearDown() async throws {
+ }
+}
diff --git a/E2E/e2eTests/TestFramework/Screenplay/Ability.swift b/E2E/e2eTests/TestFramework/Screenplay/Ability.swift
new file mode 100644
index 00000000..a187dd3f
--- /dev/null
+++ b/E2E/e2eTests/TestFramework/Screenplay/Ability.swift
@@ -0,0 +1,20 @@
+import Foundation
+
+protocol Ability {
+ /// return interface for the ability
+ associatedtype AbilityInstanceType
+
+ var abilityName: String {get}
+ var actor: Actor {get}
+
+ init(_ actor: Actor)
+
+ /// object instance returned by the ability
+ func instance() -> AbilityInstanceType
+
+ /// initialization hook, used to create the object instance for ability
+ func setUp(_ actor: Actor) async throws
+
+ /// teardown hook
+ func tearDown() async throws
+}
diff --git a/E2E/e2eTests/TestFramework/Screenplay/Actor.swift b/E2E/e2eTests/TestFramework/Screenplay/Actor.swift
new file mode 100644
index 00000000..daabe3b3
--- /dev/null
+++ b/E2E/e2eTests/TestFramework/Screenplay/Actor.swift
@@ -0,0 +1,77 @@
+import Foundation
+import XCTest
+
+class Actor {
+ var name: String
+ private var context: [String: Any] = [:]
+ private var abilities: [String : any Ability] = [:]
+
+ init(_ name: String) {
+ self.name = name
+ }
+
+ func initialize() async throws {
+ for ability in abilities.values {
+ try await ability.setUp(self)
+ }
+ }
+
+ func tearDown() async throws {
+ for ability in abilities.values {
+ try await ability.tearDown()
+ }
+ }
+
+ func whoCanUse(_ abilityType: T.Type) -> Actor {
+ let ability = abilityType.init(self)
+ abilities[String(describing: T.self)] = ability
+ return self
+ }
+
+ private func getAbility(_ ability: T.Type) -> T {
+ return self.abilities[String(describing: ability.self)]! as! T
+ }
+
+ func using(ability: T.Type,
+ action: String // = "executes an action"
+ ) throws -> T.AbilityInstanceType {
+ if !abilities.contains(where: { $0.key == String(describing: ability.self) }) {
+ throw ActorError.CantUseAbility("Actor [\(name)] don't have the ability to use [\(ability.self)]")
+ }
+ let ability = getAbility(ability)
+ TestConfiguration.shared().report(.ACTION, "\(name) \(action) using \(ability.abilityName)")
+ return ability.instance()
+ }
+
+ func waitUsingAbility(ability: T.Type,
+ action: String, // = "an expectation is met",
+ callback: (_ ability: T.AbilityInstanceType) async throws -> Bool
+ ) async throws {
+ let ability = getAbility(ability)
+ TestConfiguration.shared().report(.ACTION, "\(name) waits until \(action) using \(ability.abilityName)")
+ return try await Wait.until {
+ try await callback(ability.instance())
+ }
+ }
+
+ func remember(key: String, value: Any) throws {
+ TestConfiguration.shared().report(.ACTION, "\(name) remembers [\(key)]")
+ context[key] = value
+ }
+
+ func recall(key: String) throws -> T {
+ TestConfiguration.shared().report(.ACTION, "\(name) recalls [\(key)]")
+ XCTAssert(context[key] != nil, "Unable to recall [\(key)] all I know is \(context.keys)")
+ if (context[key] == nil) {
+ throw ActorError.CantFindNote("\(name) don't have any note named [\(key)]")
+ }
+ return context[key] as! T
+ }
+
+ /// Here we could add attempsTo where actor can run actions, wait, etc
+}
+
+enum ActorError : Error {
+ case CantUseAbility(_ message: String)
+ case CantFindNote(_ message: String)
+}
diff --git a/E2E/e2eTests/TestFramework/Screenplay/Wait.swift b/E2E/e2eTests/TestFramework/Screenplay/Wait.swift
new file mode 100644
index 00000000..72c5fcba
--- /dev/null
+++ b/E2E/e2eTests/TestFramework/Screenplay/Wait.swift
@@ -0,0 +1,21 @@
+import Foundation
+
+class Wait {
+ static func until(timeout: Int = 30, callback: () async throws -> Bool, file: StaticString = #file, line: UInt = #line) async throws {
+ let startTime = Date()
+ while try await !callback() {
+ if Date().timeIntervalSince(startTime) >= Double(timeout) {
+ throw Assertion.TimeoutError(
+ timeout: timeout,
+ file: file,
+ line: line
+ )
+ }
+ try await Task.sleep(nanoseconds: UInt64(500000000))
+ }
+ }
+}
+
+enum TimeoutError: Error {
+ case timeoutReached
+}
diff --git a/E2E/e2eTests/openapi-generator-config.yaml b/E2E/e2eTests/openapi-generator-config.yaml
new file mode 100644
index 00000000..ecefb471
--- /dev/null
+++ b/E2E/e2eTests/openapi-generator-config.yaml
@@ -0,0 +1,3 @@
+generate:
+ - types
+ - client
diff --git a/E2E/e2eTests/openapi.yaml b/E2E/e2eTests/openapi.yaml
new file mode 100644
index 00000000..9b991ad8
--- /dev/null
+++ b/E2E/e2eTests/openapi.yaml
@@ -0,0 +1,4579 @@
+openapi: 3.1.0
+info:
+ title: Prism Agent
+ version: 1.20.1
+paths:
+ /credential-definition-registry/definitions:
+ get:
+ tags:
+ - Credential Definition Registry
+ summary: Lookup credential definitions by indexed fields
+ description: 'Lookup credential definitions by `author`, `name`, `tag` parameters
+ and control the pagination by `offset` and `limit` parameters '
+ operationId: lookupCredentialDefinitionsByQuery
+ parameters:
+ - name: author
+ in: query
+ required: false
+ schema:
+ type: string
+ example: did:prism:4a5b5cf0a513e83b598bbea25cd6196746747f361a73ef77068268bc9bd732ff
+ - name: name
+ in: query
+ required: false
+ schema:
+ type: string
+ example: DrivingLicense
+ - name: version
+ in: query
+ required: false
+ schema:
+ type: string
+ example: 1.0.0
+ - name: tag
+ in: query
+ required: false
+ schema:
+ type: string
+ example: licence
+ - name: offset
+ in: query
+ required: false
+ schema:
+ type: integer
+ format: int32
+ - name: limit
+ in: query
+ required: false
+ schema:
+ type: integer
+ format: int32
+ - name: order
+ in: query
+ required: false
+ schema:
+ type: string
+ responses:
+ '200':
+ description: Collection of CredentialDefinitions records.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/CredentialDefinitionResponsePage'
+ '400':
+ description: Invalid request parameters
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '500':
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ security:
+ - apiKeyAuth: []
+ - jwtAuth: []
+ post:
+ tags:
+ - Credential Definition Registry
+ summary: Publish new definition to the definition registry
+ description: Create the new credential definition record with metadata and internal
+ JSON Schema on behalf of Cloud Agent. The credential definition will be signed
+ by the keys of Cloud Agent and issued by the DID that corresponds to it.
+ operationId: createCredentialDefinition
+ requestBody:
+ description: JSON object required for the credential definition creation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/CredentialDefinitionInput'
+ required: true
+ responses:
+ '201':
+ description: The new credential definition record is successfully created
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/CredentialDefinitionResponse'
+ '400':
+ description: Invalid request parameters
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '403':
+ description: Forbidden
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '404':
+ description: Resource could not be found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '500':
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ security:
+ - apiKeyAuth: []
+ - jwtAuth: []
+ /credential-definition-registry/definitions/{guid}:
+ get:
+ tags:
+ - Credential Definition Registry
+ summary: Fetch the credential definition from the registry by `guid`
+ description: Fetch the credential definition by the unique identifier
+ operationId: getCredentialDefinitionById
+ parameters:
+ - name: guid
+ in: path
+ description: Globally unique identifier of the credential definition record
+ required: true
+ schema:
+ type: string
+ format: uuid
+ responses:
+ '200':
+ description: CredentialDefinition found by `guid`
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/CredentialDefinitionResponse'
+ '400':
+ description: Invalid request parameters
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '404':
+ description: Resource could not be found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '500':
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ /credential-definition-registry/definitions/{guid}/definition:
+ get:
+ tags:
+ - Credential Definition Registry
+ summary: Fetch the inner definition field of the credential definition from
+ the registry by `guid`
+ description: Fetch the inner definition fields of the credential definition
+ by the unique identifier
+ operationId: getCredentialDefinitionInnerDefinitionById
+ parameters:
+ - name: guid
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ responses:
+ '200':
+ description: CredentialDefinition found by `guid`
+ content:
+ application/json:
+ schema: {}
+ '400':
+ description: Invalid request parameters
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '404':
+ description: Resource could not be found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '500':
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ /schema-registry/schemas:
+ get:
+ tags:
+ - Schema Registry
+ summary: Lookup schemas by indexed fields
+ description: 'Lookup schemas by `author`, `name`, `tags` parameters and control
+ the pagination by `offset` and `limit` parameters '
+ operationId: lookupSchemasByQuery
+ parameters:
+ - name: author
+ in: query
+ required: false
+ schema:
+ type: string
+ example: did:prism:4a5b5cf0a513e83b598bbea25cd6196746747f361a73ef77068268bc9bd732ff
+ - name: name
+ in: query
+ required: false
+ schema:
+ type: string
+ example: DrivingLicense
+ - name: version
+ in: query
+ required: false
+ schema:
+ type: string
+ example: 1.0.0
+ - name: tags
+ in: query
+ required: false
+ schema:
+ type: string
+ example: driving
+ - name: offset
+ in: query
+ required: false
+ schema:
+ type: integer
+ format: int32
+ - name: limit
+ in: query
+ required: false
+ schema:
+ type: integer
+ format: int32
+ - name: order
+ in: query
+ required: false
+ schema:
+ type: string
+ responses:
+ '200':
+ description: Collection of CredentialSchema records.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/CredentialSchemaResponsePage'
+ '400':
+ description: Invalid request parameters
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '403':
+ description: Forbidden
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '500':
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ security:
+ - apiKeyAuth: []
+ - jwtAuth: []
+ post:
+ tags:
+ - Schema Registry
+ summary: Publish new schema to the schema registry
+ description: Create the new credential schema record with metadata and internal
+ JSON Schema on behalf of Cloud Agent. The credential schema will be signed
+ by the keys of Cloud Agent and issued by the DID that corresponds to it.
+ operationId: createSchema
+ requestBody:
+ description: JSON object required for the credential schema creation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/CredentialSchemaInput'
+ required: true
+ responses:
+ '201':
+ description: The new credential schema record is successfully created
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/CredentialSchemaResponse'
+ '400':
+ description: Invalid request parameters
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '403':
+ description: Forbidden
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '404':
+ description: Resource could not be found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '500':
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ security:
+ - apiKeyAuth: []
+ - jwtAuth: []
+ /schema-registry/{author}/{id}:
+ put:
+ tags:
+ - Schema Registry
+ summary: Publish the new version of the credential schema to the schema registry
+ description: Publish the new version of the credential schema record with metadata
+ and internal JSON Schema on behalf of Cloud Agent. The credential schema will
+ be signed by the keys of Cloud Agent and issued by the DID that corresponds
+ to it.
+ operationId: updateSchema
+ parameters:
+ - name: author
+ in: path
+ description: DID of the identity which authored the credential schema. A piece
+ of Metadata.
+ required: true
+ schema:
+ type: string
+ - name: id
+ in: path
+ description: A locally unique identifier to address the schema. UUID is generated
+ by the backend.
+ required: true
+ schema:
+ type: string
+ format: uuid
+ requestBody:
+ description: JSON object required for the credential schema update
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/CredentialSchemaInput'
+ required: true
+ responses:
+ '200':
+ description: The credential schema record is successfully updated
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/CredentialSchemaResponse'
+ '400':
+ description: Invalid request parameters
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '403':
+ description: Forbidden
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '404':
+ description: Resource could not be found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '500':
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ security:
+ - apiKeyAuth: []
+ - jwtAuth: []
+ /schema-registry/schemas/{guid}:
+ get:
+ tags:
+ - Schema Registry
+ summary: Fetch the schema from the registry by `guid`
+ description: Fetch the credential schema by the unique identifier
+ operationId: getSchemaById
+ parameters:
+ - name: guid
+ in: path
+ description: Globally unique identifier of the credential schema record
+ required: true
+ schema:
+ type: string
+ format: uuid
+ responses:
+ '200':
+ description: CredentialSchema found by `guid`
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/CredentialSchemaResponse'
+ '400':
+ description: Invalid request parameters
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '404':
+ description: Resource could not be found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '500':
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ /schema-registry/test:
+ get:
+ tags:
+ - Schema Registry
+ summary: Trace the request input from the point of view of the server
+ description: Trace the request input from the point of view of the server
+ operationId: test
+ responses:
+ '200':
+ description: ''
+ content:
+ application/json:
+ schema:
+ type: string
+ '400':
+ description: Invalid request parameters
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '403':
+ description: Forbidden
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '500':
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ security:
+ - apiKeyAuth: []
+ - jwtAuth: []
+ /verification/policies:
+ get:
+ tags:
+ - Verification
+ summary: Lookup verification policies by query
+ description: Lookup verification policies by `name`, and control the pagination
+ by `offset` and `limit` parameters
+ operationId: lookupVerificationPoliciesByQuery
+ parameters:
+ - name: name
+ in: query
+ required: false
+ schema:
+ type: string
+ - name: offset
+ in: query
+ required: false
+ schema:
+ type: integer
+ format: int32
+ - name: limit
+ in: query
+ required: false
+ schema:
+ type: integer
+ format: int32
+ - name: order
+ in: query
+ required: false
+ schema:
+ type: string
+ responses:
+ '200':
+ description: ''
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/VerificationPolicyPage'
+ '400':
+ description: Invalid request parameters
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '403':
+ description: Forbidden
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '500':
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ security:
+ - apiKeyAuth: []
+ - jwtAuth: []
+ post:
+ tags:
+ - Verification
+ summary: Create the new verification policy
+ description: Create the new verification policy
+ operationId: createVerificationPolicy
+ requestBody:
+ description: Create verification policy object
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/VerificationPolicyInput'
+ required: true
+ responses:
+ '201':
+ description: Created verification policy entity
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/VerificationPolicy'
+ '400':
+ description: Invalid request parameters
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '403':
+ description: Forbidden
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '500':
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ security:
+ - apiKeyAuth: []
+ - jwtAuth: []
+ /verification/policies/{id}:
+ get:
+ tags:
+ - Verification
+ summary: Fetch the verification policy by id
+ description: Get the verification policy by id
+ operationId: getVerificationPolicyById
+ parameters:
+ - name: id
+ in: path
+ description: Get the verification policy by id
+ required: true
+ schema:
+ type: string
+ format: uuid
+ responses:
+ '200':
+ description: ''
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/VerificationPolicy'
+ '400':
+ description: Invalid request parameters
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '403':
+ description: Forbidden
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '404':
+ description: Resource could not be found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '500':
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ security:
+ - apiKeyAuth: []
+ - jwtAuth: []
+ put:
+ tags:
+ - Verification
+ summary: Update the verification policy object by id
+ description: Update the verification policy entry
+ operationId: updateVerificationPolicy
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - name: nonce
+ in: query
+ description: Nonce of the previous VerificationPolicy
+ required: true
+ schema:
+ type: integer
+ format: int32
+ requestBody:
+ description: Update verification policy object
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/VerificationPolicyInput'
+ required: true
+ responses:
+ '200':
+ description: ''
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/VerificationPolicy'
+ '400':
+ description: Invalid request parameters
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '403':
+ description: Forbidden
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '404':
+ description: Resource could not be found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '500':
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ security:
+ - apiKeyAuth: []
+ - jwtAuth: []
+ delete:
+ tags:
+ - Verification
+ summary: Deleted the verification policy by id
+ description: Delete the verification policy by id
+ operationId: deleteVerificationPolicyById
+ parameters:
+ - name: id
+ in: path
+ description: Delete the verification policy by id
+ required: true
+ schema:
+ type: string
+ format: uuid
+ responses:
+ '200':
+ description: Verification policy deleted successfully
+ '400':
+ description: Invalid request parameters
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '403':
+ description: Forbidden
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '404':
+ description: Resource could not be found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '500':
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ security:
+ - apiKeyAuth: []
+ - jwtAuth: []
+ /connections:
+ get:
+ tags:
+ - Connections Management
+ summary: Gets the list of connection records.
+ description: Get the list of connection records paginated
+ operationId: getConnections
+ parameters:
+ - name: offset
+ in: query
+ required: false
+ schema:
+ type: integer
+ format: int32
+ - name: limit
+ in: query
+ required: false
+ schema:
+ type: integer
+ format: int32
+ - name: thid
+ in: query
+ description: The thid of a DIDComm communication.
+ required: false
+ schema:
+ type: string
+ responses:
+ '200':
+ description: The list of connection records.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ConnectionsPage'
+ '400':
+ description: Invalid request parameters
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '403':
+ description: Forbidden
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '500':
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ security:
+ - apiKeyAuth: []
+ - jwtAuth: []
+ post:
+ tags:
+ - Connections Management
+ summary: Creates a new connection record and returns an Out of Band invitation.
+ description: |2
+
+ Generates a new Peer DID and creates an [Out of Band 2.0](https://identity.foundation/didcomm-messaging/spec/v2.0/#out-of-band-messages) invitation.
+ It returns a new connection record in `InvitationGenerated` state.
+ The request body may contain a `label` that can be used as a human readable alias for the connection, for example `{'label': "Bob"}`
+ operationId: createConnection
+ requestBody:
+ description: JSON object required for the connection creation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/CreateConnectionRequest'
+ required: true
+ responses:
+ '201':
+ description: The connection record was created successfully, and is returned
+ in the response body.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Connection'
+ '400':
+ description: Invalid request parameters
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '403':
+ description: Forbidden
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '500':
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ security:
+ - apiKeyAuth: []
+ - jwtAuth: []
+ /connections/{connectionId}:
+ get:
+ tags:
+ - Connections Management
+ summary: Gets an existing connection record by its unique identifier.
+ description: Gets an existing connection record by its unique identifier
+ operationId: getConnection
+ parameters:
+ - name: connectionId
+ in: path
+ description: The unique identifier of the connection record.
+ required: true
+ schema:
+ type: string
+ format: uuid
+ responses:
+ '200':
+ description: The connection record.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Connection'
+ '400':
+ description: Invalid request parameters
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '403':
+ description: Forbidden
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '404':
+ description: Resource could not be found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '500':
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ security:
+ - apiKeyAuth: []
+ - jwtAuth: []
+ /connection-invitations:
+ post:
+ tags:
+ - Connections Management
+ summary: Accepts an Out of Band invitation.
+ description: |2
+
+ Accepts an [Out of Band 2.0](https://identity.foundation/didcomm-messaging/spec/v2.0/#out-of-band-messages) invitation, generates a new Peer DID,
+ and submits a Connection Request to the inviter.
+ It returns a connection object in `ConnectionRequestPending` state, until the Connection Request is eventually sent to the inviter by the prism-agent's background process. The connection object state will then automatically move to `ConnectionRequestSent`.
+ operationId: acceptConnectionInvitation
+ requestBody:
+ description: The request used by an invitee to accept a connection invitation
+ received from an inviter, using out-of-band mechanism.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/AcceptConnectionInvitationRequest'
+ required: true
+ responses:
+ '200':
+ description: The invitation was successfully accepted.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Connection'
+ '400':
+ description: Invalid request parameters
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '403':
+ description: Forbidden
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '500':
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ security:
+ - apiKeyAuth: []
+ - jwtAuth: []
+ /dids/{didRef}:
+ get:
+ tags:
+ - DID
+ summary: Resolve Prism DID to a W3C representation
+ description: |
+ Resolve Prism DID to a W3C DID document representation.
+ The response can be the [DID resolution result](https://w3c-ccg.github.io/did-resolution/#did-resolution-result)
+ or [DID document representation](https://www.w3.org/TR/did-core/#representations) depending on the `Accept` request header.
+ The response is implemented according to [resolver HTTP binding](https://w3c-ccg.github.io/did-resolution/#bindings-https) in the DID resolution spec.
+ operationId: getDID
+ parameters:
+ - name: didRef
+ in: path
+ description: Prism DID according to [the Prism DID method syntax](https://github.com/input-output-hk/prism-did-method-spec/blob/main/w3c-spec/PRISM-method.md#prism-did-method-syntax)
+ required: true
+ schema:
+ type: string
+ example: did:prism:4a5b5cf0a513e83b598bbea25cd6196746747f361a73ef77068268bc9bd732ff
+ responses:
+ '200':
+ description: ''
+ content:
+ application/ld+json; profile=https://w3id.org/did-resolution:
+ schema:
+ $ref: '#/components/schemas/DIDResolutionResult'
+ application/did+ld+json:
+ schema:
+ $ref: '#/components/schemas/DIDDocument'
+ '400':
+ description: ''
+ content:
+ application/ld+json; profile=https://w3id.org/did-resolution:
+ schema:
+ $ref: '#/components/schemas/DIDResolutionResult'
+ application/did+ld+json:
+ schema:
+ type: string
+ description: Empty representation
+ format: binary
+ example: ''
+ '404':
+ description: ''
+ content:
+ application/ld+json; profile=https://w3id.org/did-resolution:
+ schema:
+ $ref: '#/components/schemas/DIDResolutionResult'
+ application/did+ld+json:
+ schema:
+ type: string
+ description: Empty representation
+ format: binary
+ example: ''
+ '406':
+ description: ''
+ content:
+ application/ld+json; profile=https://w3id.org/did-resolution:
+ schema:
+ $ref: '#/components/schemas/DIDResolutionResult'
+ application/did+ld+json:
+ schema:
+ type: string
+ description: Empty representation
+ format: binary
+ example: ''
+ '410':
+ description: ''
+ content:
+ application/ld+json; profile=https://w3id.org/did-resolution:
+ schema:
+ $ref: '#/components/schemas/DIDResolutionResult'
+ application/did+ld+json:
+ schema:
+ type: string
+ description: Empty representation
+ format: binary
+ example: ''
+ '500':
+ description: ''
+ content:
+ application/ld+json; profile=https://w3id.org/did-resolution:
+ schema:
+ $ref: '#/components/schemas/DIDResolutionResult'
+ application/did+ld+json:
+ schema:
+ type: string
+ description: Empty representation
+ format: binary
+ example: ''
+ '501':
+ description: ''
+ content:
+ application/ld+json; profile=https://w3id.org/did-resolution:
+ schema:
+ $ref: '#/components/schemas/DIDResolutionResult'
+ application/did+ld+json:
+ schema:
+ type: string
+ description: Empty representation
+ format: binary
+ example: ''
+ /did-registrar/dids:
+ get:
+ tags:
+ - DID Registrar
+ summary: List all DIDs stored in Prism Agent's wallet
+ description: |-
+ List all DIDs stored in Prism Agent's wallet.
+ Return a paginated items ordered by created timestamp.
+ If the `limit` parameter is not set, it defaults to 100 items per page.
+ operationId: getDid-registrarDids
+ parameters:
+ - name: offset
+ in: query
+ required: false
+ schema:
+ type: integer
+ format: int32
+ - name: limit
+ in: query
+ required: false
+ schema:
+ type: integer
+ format: int32
+ responses:
+ '200':
+ description: List Prism Agent managed DIDs
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ManagedDIDPage'
+ '400':
+ description: Invalid request parameters
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '403':
+ description: Forbidden
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '500':
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ security:
+ - apiKeyAuth: []
+ - jwtAuth: []
+ post:
+ tags:
+ - DID Registrar
+ summary: Create unpublished DID and store it in Prism Agent's wallet
+ description: |-
+ Create unpublished DID and store it inside Prism Agent's wallet. The private keys of the DID is
+ managed by Prism Agent. The DID can later be published to the VDR using publications endpoint.
+ operationId: postDid-registrarDids
+ requestBody:
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/CreateManagedDidRequest'
+ required: true
+ responses:
+ '201':
+ description: Created unpublished DID.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/CreateManagedDIDResponse'
+ '400':
+ description: Invalid request parameters
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '403':
+ description: Forbidden
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '404':
+ description: Resource could not be found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '422':
+ description: Unable to process the request
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '500':
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ security:
+ - apiKeyAuth: []
+ - jwtAuth: []
+ /did-registrar/dids/{didRef}:
+ get:
+ tags:
+ - DID Registrar
+ summary: Get DID stored in Prism Agent's wallet
+ description: Get DID stored in Prism Agent's wallet
+ operationId: getDid-registrarDidsDidref
+ parameters:
+ - name: didRef
+ in: path
+ description: Prism DID according to [the Prism DID method syntax](https://github.com/input-output-hk/prism-did-method-spec/blob/main/w3c-spec/PRISM-method.md#prism-did-method-syntax)
+ required: true
+ schema:
+ type: string
+ example: did:prism:4a5b5cf0a513e83b598bbea25cd6196746747f361a73ef77068268bc9bd732ff
+ responses:
+ '200':
+ description: Get Prism Agent managed DID
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ManagedDID'
+ '400':
+ description: Invalid request parameters
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '403':
+ description: Forbidden
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '404':
+ description: Resource could not be found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '500':
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ security:
+ - apiKeyAuth: []
+ - jwtAuth: []
+ /did-registrar/dids/{didRef}/publications:
+ post:
+ tags:
+ - DID Registrar
+ summary: Publish the DID stored in Prism Agent's wallet to the VDR
+ description: Publish the DID stored in Prism Agent's wallet to the VDR.
+ operationId: postDid-registrarDidsDidrefPublications
+ parameters:
+ - name: didRef
+ in: path
+ description: Prism DID according to [the Prism DID method syntax](https://github.com/input-output-hk/prism-did-method-spec/blob/main/w3c-spec/PRISM-method.md#prism-did-method-syntax)
+ required: true
+ schema:
+ type: string
+ example: did:prism:4a5b5cf0a513e83b598bbea25cd6196746747f361a73ef77068268bc9bd732ff
+ responses:
+ '202':
+ description: Publishing DID to the VDR.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/DIDOperationResponse'
+ '400':
+ description: Invalid request parameters
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '403':
+ description: Forbidden
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '404':
+ description: Resource could not be found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '500':
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ security:
+ - apiKeyAuth: []
+ - jwtAuth: []
+ /did-registrar/dids/{didRef}/updates:
+ post:
+ tags:
+ - DID Registrar
+ summary: Update DID in Prism Agent's wallet and post update operation to the
+ VDR
+ description: |-
+ Update DID in Prism Agent's wallet and post update operation to the VDR.
+ This endpoint updates the DID document from the last confirmed operation.
+ Submitting multiple update operations without waiting for confirmation will result in
+ some operations being rejected as only one operation is allowed to be appended to the last confirmed operation.
+ operationId: postDid-registrarDidsDidrefUpdates
+ parameters:
+ - name: didRef
+ in: path
+ description: Prism DID according to [the Prism DID method syntax](https://github.com/input-output-hk/prism-did-method-spec/blob/main/w3c-spec/PRISM-method.md#prism-did-method-syntax)
+ required: true
+ schema:
+ type: string
+ example: did:prism:4a5b5cf0a513e83b598bbea25cd6196746747f361a73ef77068268bc9bd732ff
+ requestBody:
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/UpdateManagedDIDRequest'
+ required: true
+ responses:
+ '202':
+ description: DID update operation accepted
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/DIDOperationResponse'
+ '400':
+ description: Invalid request parameters
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '403':
+ description: Forbidden
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '404':
+ description: Resource could not be found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '409':
+ description: Cannot process due to conflict with current state of the resource
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '422':
+ description: Unable to process the request
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '500':
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ security:
+ - apiKeyAuth: []
+ - jwtAuth: []
+ /did-registrar/dids/{didRef}/deactivations:
+ post:
+ tags:
+ - DID Registrar
+ summary: Deactivate DID in Prism Agent's wallet and post deactivate operation
+ to the VDR
+ description: Deactivate DID in Prism Agent's wallet and post deactivate operation
+ to the VDR.
+ operationId: postDid-registrarDidsDidrefDeactivations
+ parameters:
+ - name: didRef
+ in: path
+ description: Prism DID according to [the Prism DID method syntax](https://github.com/input-output-hk/prism-did-method-spec/blob/main/w3c-spec/PRISM-method.md#prism-did-method-syntax)
+ required: true
+ schema:
+ type: string
+ example: did:prism:4a5b5cf0a513e83b598bbea25cd6196746747f361a73ef77068268bc9bd732ff
+ responses:
+ '202':
+ description: DID deactivation operation accepted
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/DIDOperationResponse'
+ '400':
+ description: Invalid request parameters
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '403':
+ description: Forbidden
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '404':
+ description: Resource could not be found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '422':
+ description: Unable to process the request
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '500':
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ security:
+ - apiKeyAuth: []
+ - jwtAuth: []
+ /issue-credentials/credential-offers:
+ post:
+ tags:
+ - Issue Credentials Protocol
+ summary: As a credential issuer, create a new credential offer to be sent to
+ a holder.
+ description: Creates a new credential offer in the database
+ operationId: createCredentialOffer
+ requestBody:
+ description: The credential offer object.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/CreateIssueCredentialRecordRequest'
+ required: true
+ responses:
+ '201':
+ description: The issue credential record.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/IssueCredentialRecord'
+ '400':
+ description: Invalid request parameters
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '403':
+ description: Forbidden
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '404':
+ description: Resource could not be found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '500':
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ security:
+ - apiKeyAuth: []
+ - jwtAuth: []
+ /issue-credentials/records:
+ get:
+ tags:
+ - Issue Credentials Protocol
+ summary: Gets the list of issue credential records.
+ description: Get the list of issue credential records paginated
+ operationId: getCredentialRecords
+ parameters:
+ - name: offset
+ in: query
+ required: false
+ schema:
+ type: integer
+ format: int32
+ - name: limit
+ in: query
+ required: false
+ schema:
+ type: integer
+ format: int32
+ - name: thid
+ in: query
+ description: The thid of a DIDComm communication.
+ required: false
+ schema:
+ type: string
+ responses:
+ '200':
+ description: The list of issue credential records.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/IssueCredentialRecordPage'
+ '400':
+ description: Invalid request parameters
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '403':
+ description: Forbidden
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '500':
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ security:
+ - apiKeyAuth: []
+ - jwtAuth: []
+ /issue-credentials/records/{recordId}:
+ get:
+ tags:
+ - Issue Credentials Protocol
+ summary: Gets an existing issue credential record by its unique identifier.
+ description: Gets issue credential records by record id
+ operationId: getCredentialRecord
+ parameters:
+ - name: recordId
+ in: path
+ description: The unique identifier of the issue credential record.
+ required: true
+ schema:
+ type: string
+ responses:
+ '200':
+ description: The issue credential record.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/IssueCredentialRecord'
+ '400':
+ description: Invalid request parameters
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '403':
+ description: Forbidden
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '404':
+ description: Resource could not be found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '500':
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ security:
+ - apiKeyAuth: []
+ - jwtAuth: []
+ /issue-credentials/records/{recordId}/accept-offer:
+ post:
+ tags:
+ - Issue Credentials Protocol
+ summary: As a holder, accepts a credential offer received from an issuer.
+ description: Accepts a credential offer received from a VC issuer and sends
+ back a credential request.
+ operationId: acceptCredentialOffer
+ parameters:
+ - name: recordId
+ in: path
+ description: The unique identifier of the issue credential record.
+ required: true
+ schema:
+ type: string
+ requestBody:
+ description: The accept credential offer request object.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/AcceptCredentialOfferRequest'
+ required: true
+ responses:
+ '200':
+ description: The issue credential offer was successfully accepted.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/IssueCredentialRecord'
+ '400':
+ description: Invalid request parameters
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '403':
+ description: Forbidden
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '404':
+ description: Resource could not be found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '500':
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ security:
+ - apiKeyAuth: []
+ - jwtAuth: []
+ /issue-credentials/records/{recordId}/issue-credential:
+ post:
+ tags:
+ - Issue Credentials Protocol
+ summary: As an issuer, issues the verifiable credential related to the specified
+ record.
+ description: Sends credential to a holder (holder DID is specified in credential
+ as subjectDid). Credential is constructed from the credential records found
+ by credential id.
+ operationId: issueCredential
+ parameters:
+ - name: recordId
+ in: path
+ description: The unique identifier of the issue credential record.
+ required: true
+ schema:
+ type: string
+ responses:
+ '200':
+ description: The request was processed successfully and the credential will
+ be issued asynchronously.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/IssueCredentialRecord'
+ '400':
+ description: Invalid request parameters
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '403':
+ description: Forbidden
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '404':
+ description: Resource could not be found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '500':
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ security:
+ - apiKeyAuth: []
+ - jwtAuth: []
+ /present-proof/presentations:
+ get:
+ tags:
+ - Present Proof
+ summary: Gets the list of proof presentation records.
+ description: list of presentation statuses
+ operationId: getAllPresentation
+ parameters:
+ - name: offset
+ in: query
+ required: false
+ schema:
+ type: integer
+ format: int32
+ - name: limit
+ in: query
+ required: false
+ schema:
+ type: integer
+ format: int32
+ - name: thid
+ in: query
+ required: false
+ schema:
+ type: string
+ responses:
+ '200':
+ description: The list of proof presentation records.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/PresentationStatusPage'
+ '400':
+ description: Invalid request parameters
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '403':
+ description: Forbidden
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '500':
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ security:
+ - apiKeyAuth: []
+ - jwtAuth: []
+ post:
+ tags:
+ - Present Proof
+ summary: As a Verifier, create a new proof presentation request and send it
+ to the Prover.
+ description: Holder presents proof derived from the verifiable credential to
+ verifier.
+ operationId: requestPresentation
+ requestBody:
+ description: The present proof creation request.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/RequestPresentationInput'
+ required: true
+ responses:
+ '201':
+ description: The proof presentation request was created successfully and
+ will be sent asynchronously to the Prover.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/PresentationStatus'
+ '400':
+ description: Invalid request parameters
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '403':
+ description: Forbidden
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '404':
+ description: Resource could not be found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '500':
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ security:
+ - apiKeyAuth: []
+ - jwtAuth: []
+ /present-proof/presentations/{presentationId}:
+ get:
+ tags:
+ - Present Proof
+ summary: Gets an existing proof presentation record by its unique identifier.
+ More information on the error can be found in the response body.
+ description: Returns an existing presentation record by id.
+ operationId: getPresentation
+ parameters:
+ - name: presentationId
+ in: path
+ description: The unique identifier of the presentation record.
+ required: true
+ schema:
+ type: string
+ format: uuid
+ responses:
+ '200':
+ description: The proof presentation record.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/PresentationStatus'
+ '400':
+ description: Invalid request parameters
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '403':
+ description: Forbidden
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '404':
+ description: Resource could not be found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '500':
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ security:
+ - apiKeyAuth: []
+ - jwtAuth: []
+ patch:
+ tags:
+ - Present Proof
+ summary: Updates the proof presentation record matching the unique identifier,
+ with the specific action to perform.
+ description: Accept or reject presentation of proof request.
+ operationId: updatePresentation
+ parameters:
+ - name: presentationId
+ in: path
+ description: The unique identifier of the presentation record.
+ required: true
+ schema:
+ type: string
+ format: uuid
+ requestBody:
+ description: The action to perform on the proof presentation record.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/RequestPresentationAction'
+ required: true
+ responses:
+ '200':
+ description: The proof presentation record was successfully updated.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/PresentationStatus'
+ '400':
+ description: Invalid request parameters
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '403':
+ description: Forbidden
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '404':
+ description: Resource could not be found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '500':
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ security:
+ - apiKeyAuth: []
+ - jwtAuth: []
+ /_system/health:
+ get:
+ tags:
+ - System
+ summary: As a system user, check the health status of the running service
+ description: Returns the health info object of the running service
+ operationId: systemHealth
+ responses:
+ '200':
+ description: The health info object.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/HealthInfo'
+ '400':
+ description: Invalid request parameters
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '500':
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ /_system/metrics:
+ get:
+ tags:
+ - System
+ summary: As a system user, check the health status of the running service
+ description: Returns the health info object of the running service
+ operationId: systemMetrics
+ responses:
+ '200':
+ description: The metrics as pain strings.
+ content:
+ text/plain:
+ schema:
+ type: string
+ '400':
+ description: Invalid request parameters
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '500':
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ /iam/entities:
+ get:
+ tags:
+ - Identity and Access Management
+ summary: Get all entities
+ description: 'Get all entities with the pagination by `offset` and `limit` parameters '
+ operationId: getAllEntities
+ parameters:
+ - name: offset
+ in: query
+ required: false
+ schema:
+ type: integer
+ format: int32
+ - name: limit
+ in: query
+ required: false
+ schema:
+ type: integer
+ format: int32
+ responses:
+ '200':
+ description: Collection of Entity records
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/EntityResponsePage'
+ '400':
+ description: Invalid request parameters
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '403':
+ description: Forbidden
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '500':
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ security:
+ - {}
+ - adminApiKeyAuth: []
+ post:
+ tags:
+ - Identity and Access Management
+ summary: Create a new entity record
+ description: Create the new entity record. The entity record is a representation
+ of the account in the system.
+ operationId: createEntity
+ requestBody:
+ description: JSON object required for the entity creation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/CreateEntityRequest'
+ required: true
+ responses:
+ '201':
+ description: The new entity is successfully created
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/EntityResponse'
+ '400':
+ description: Invalid request parameters
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '403':
+ description: Forbidden
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '404':
+ description: Resource could not be found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '500':
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ security:
+ - {}
+ - adminApiKeyAuth: []
+ /iam/entities/{id}/name:
+ put:
+ tags:
+ - Identity and Access Management
+ summary: Update the entity record name by `id`
+ description: Update the entity record name by `id`
+ operationId: updateEntityName
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ requestBody:
+ description: JSON object required for the entity name update
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/UpdateEntityNameRequest'
+ required: true
+ responses:
+ '200':
+ description: The entity record is successfully updated
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/EntityResponse'
+ '400':
+ description: Invalid request parameters
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '403':
+ description: Forbidden
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '404':
+ description: Resource could not be found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '500':
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ security:
+ - {}
+ - adminApiKeyAuth: []
+ /iam/entities/{id}/walletId:
+ put:
+ tags:
+ - Identity and Access Management
+ summary: Update the entity record `walletId` by `id`
+ description: Update the entity record `walletId` field by `id`
+ operationId: updateEntityWalletId
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ requestBody:
+ description: JSON object required for the entity walletId update
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/UpdateEntityWalletIdRequest'
+ required: true
+ responses:
+ '200':
+ description: The entity record is successfully updated
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/EntityResponse'
+ '400':
+ description: Invalid request parameters
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '403':
+ description: Forbidden
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '404':
+ description: Resource could not be found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '500':
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ security:
+ - {}
+ - adminApiKeyAuth: []
+ /iam/entities/{id}:
+ get:
+ tags:
+ - Identity and Access Management
+ summary: Get the entity by the `id`
+ description: Get the entity by the unique identifier
+ operationId: getEntityById
+ parameters:
+ - name: id
+ in: path
+ description: Identifier of the entity
+ required: true
+ schema:
+ type: string
+ format: uuid
+ responses:
+ '200':
+ description: Entity found by `id`
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/EntityResponse'
+ '400':
+ description: Invalid request parameters
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '403':
+ description: Forbidden
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '404':
+ description: Resource could not be found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '500':
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ security:
+ - {}
+ - adminApiKeyAuth: []
+ delete:
+ tags:
+ - Identity and Access Management
+ summary: Delete the entity by `id`
+ description: Delete the entity by the unique identifier
+ operationId: deleteEntityById
+ parameters:
+ - name: id
+ in: path
+ description: Identifier of the entity
+ required: true
+ schema:
+ type: string
+ format: uuid
+ responses:
+ '200':
+ description: Entity deleted successfully
+ '400':
+ description: Invalid request parameters
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '403':
+ description: Forbidden
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '404':
+ description: Resource could not be found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '500':
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ security:
+ - {}
+ - adminApiKeyAuth: []
+ /iam/apikey-authentication:
+ post:
+ tags:
+ - Identity and Access Management
+ summary: Register the `apikey` for the entity
+ description: Register the `apikey` for the entity.
+ operationId: addEntityApiKeyAuthentication
+ requestBody:
+ description: JSON object required for the registering the entity and `apikey`
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ApiKeyAuthenticationRequest'
+ required: true
+ responses:
+ '201':
+ description: The new `apikey` is successfully registered for the entity
+ '400':
+ description: Invalid request parameters
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '403':
+ description: Forbidden
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '404':
+ description: Resource could not be found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '500':
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ security:
+ - {}
+ - adminApiKeyAuth: []
+ delete:
+ tags:
+ - Identity and Access Management
+ summary: Unregister the `apikey` for the entity
+ description: Unregister the `apikey` for the entity.
+ operationId: deleteEntityApiKeyAuthentication
+ requestBody:
+ description: JSON object required for the unregistering the entity and `apikey`
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ApiKeyAuthenticationRequest'
+ required: true
+ responses:
+ '200':
+ description: The new `apikey` is successfully unregistered for the entity
+ '400':
+ description: Invalid request parameters
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '403':
+ description: Forbidden
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '404':
+ description: Resource could not be found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '500':
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ security:
+ - {}
+ - adminApiKeyAuth: []
+ /wallets:
+ get:
+ tags:
+ - Wallet Management
+ summary: List all wallets
+ operationId: getWallets
+ parameters:
+ - name: offset
+ in: query
+ required: false
+ schema:
+ type: integer
+ format: int32
+ - name: limit
+ in: query
+ required: false
+ schema:
+ type: integer
+ format: int32
+ responses:
+ '200':
+ description: Successfully list all the wallets
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/WalletDetailPage'
+ '400':
+ description: Invalid request parameters
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '403':
+ description: Forbidden
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '500':
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ security:
+ - adminApiKeyAuth: []
+ - apiKeyAuth: []
+ - jwtAuth: []
+ post:
+ tags:
+ - Wallet Management
+ summary: Create a new wallet
+ description: |-
+ Create a new wallet with optional to use provided seed.
+ The seed will be used for DID key derivation inside the wallet.
+ operationId: createWallet
+ requestBody:
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/CreateWalletRequest'
+ required: true
+ responses:
+ '201':
+ description: A new wallet has been created
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/WalletDetail'
+ '400':
+ description: Invalid request parameters
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '403':
+ description: Forbidden
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '500':
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ security:
+ - adminApiKeyAuth: []
+ - apiKeyAuth: []
+ - jwtAuth: []
+ /wallets/{walletId}:
+ get:
+ tags:
+ - Wallet Management
+ summary: Get the wallet by ID
+ operationId: getWalletsWalletid
+ parameters:
+ - name: walletId
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ responses:
+ '200':
+ description: Successfully get the wallet
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/WalletDetail'
+ '400':
+ description: Invalid request parameters
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '403':
+ description: Forbidden
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '404':
+ description: Resource could not be found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '500':
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ security:
+ - adminApiKeyAuth: []
+ - apiKeyAuth: []
+ - jwtAuth: []
+ /wallets/{walletId}/uma-permissions:
+ post:
+ tags:
+ - Wallet Management
+ summary: Create a UMA resource permission on an authorization server for the
+ wallet.
+ operationId: createWalletUmaPermission
+ parameters:
+ - name: walletId
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ requestBody:
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/CreateWalletUmaPermissionRequest'
+ required: true
+ responses:
+ '200':
+ description: UMA resource permission is created on an authorization server.
+ '400':
+ description: Invalid request parameters
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '403':
+ description: Forbidden
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '500':
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ security:
+ - adminApiKeyAuth: []
+ - apiKeyAuth: []
+ - jwtAuth: []
+ delete:
+ tags:
+ - Wallet Management
+ summary: Delete a UMA resource permission on an authorization server for the
+ wallet.
+ operationId: deleteWalletUmaPermission
+ parameters:
+ - name: walletId
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - name: subject
+ in: query
+ required: true
+ schema:
+ type: string
+ format: uuid
+ responses:
+ '200':
+ description: UMA resource permission is removed from an authorization server.
+ '400':
+ description: Invalid request parameters
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '403':
+ description: Forbidden
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '500':
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ security:
+ - adminApiKeyAuth: []
+ - apiKeyAuth: []
+ - jwtAuth: []
+ /events/webhooks:
+ get:
+ tags:
+ - Events
+ summary: List wallet webhook notifications
+ operationId: getEventsWebhooks
+ responses:
+ '200':
+ description: List wallet webhook notifications
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/WebhookNotificationPage'
+ '400':
+ description: Invalid request parameters
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '403':
+ description: Forbidden
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '500':
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ security:
+ - apiKeyAuth: []
+ - jwtAuth: []
+ post:
+ tags:
+ - Events
+ summary: Create wallet webhook notifications
+ operationId: postEventsWebhooks
+ requestBody:
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/CreateWebhookNotification'
+ required: true
+ responses:
+ '200':
+ description: Webhook notification has been created successfully
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/WebhookNotification'
+ '400':
+ description: Invalid request parameters
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '403':
+ description: Forbidden
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '409':
+ description: Cannot process due to conflict with current state of the resource
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '500':
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ security:
+ - apiKeyAuth: []
+ - jwtAuth: []
+ /events/webhooks/{id}:
+ delete:
+ tags:
+ - Events
+ summary: Delete the wallet webhook notification by `id`
+ operationId: deleteEventsWebhooksId
+ parameters:
+ - name: id
+ in: path
+ description: ID of the webhook notification to delete.
+ required: true
+ schema:
+ type: string
+ format: uuid
+ responses:
+ '200':
+ description: Webhook notification has been deleted.
+ '400':
+ description: Invalid request parameters
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '403':
+ description: Forbidden
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '404':
+ description: Resource could not be found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '500':
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ security:
+ - apiKeyAuth: []
+ - jwtAuth: []
+components:
+ schemas:
+ AcceptConnectionInvitationRequest:
+ required:
+ - invitation
+ type: object
+ properties:
+ invitation:
+ type: string
+ description: The base64-encoded raw invitation.
+ example: eyJAaWQiOiIzZmE4NWY2NC01NzE3LTQ1NjItYjNmYy0yYzk2M2Y2NmFmYTYiLCJAdHlwZSI6Imh0dHBzOi8vZGlkY29tbS5vcmcvbXktZmFtaWx5LzEuMC9teS1tZXNzYWdlLXR5cGUiLCJkaWQiOiJXZ1d4cXp0ck5vb0c5MlJYdnhTVFd2IiwiaW1hZ2VVcmwiOiJodHRwOi8vMTkyLjE2OC41Ni4xMDEvaW1nL2xvZ28uanBnIiwibGFiZWwiOiJCb2IiLCJyZWNpcGllbnRLZXlzIjpbIkgzQzJBVnZMTXY2Z21NTmFtM3VWQWpacGZrY0pDd0R3blpuNnozd1htcVBWIl0sInJvdXRpbmdLZXlzIjpbIkgzQzJBVnZMTXY2Z21NTmFtM3VWQWpacGZrY0pDd0R3blpuNnozd1htcVBWIl0sInNlcnZpY2VFbmRwb2ludCI6Imh0dHA6Ly8xOTIuMTY4LjU2LjEwMTo4MDIwIn0=
+ AcceptCredentialOfferRequest:
+ type: object
+ properties:
+ subjectId:
+ type: string
+ description: The short-form subject Prism DID to which the JWT verifiable
+ credential will be issued.This parameter is used for JWT credentials only.
+ example: did:prism:3bb0505d13fcb04d28a48234edb27b0d4e6d7e18a81e2c1abab58f3bbc21ce6f
+ ActionType:
+ type: string
+ enum:
+ - ADD_KEY
+ - ADD_SERVICE
+ - PATCH_CONTEXT
+ - REMOVE_KEY
+ - REMOVE_SERVICE
+ - UPDATE_SERVICE
+ ApiKeyAuthenticationRequest:
+ required:
+ - entityId
+ - apiKey
+ type: object
+ properties:
+ entityId:
+ type: string
+ description: The `entityId` of the entity to be updated
+ format: uuid
+ example: 01234567-0000-0000-0000-000000000000
+ apiKey:
+ type: string
+ description: The `apikey` of the entity to be updated
+ example: dkflks3DflkFmkllnDfde
+ minLength: 16
+ maxLength: 128
+ Arr:
+ type: object
+ properties:
+ elements:
+ type: array
+ items: {}
+ Bool:
+ required:
+ - value
+ type: object
+ properties:
+ value:
+ type: boolean
+ Connection:
+ required:
+ - connectionId
+ - thid
+ - role
+ - state
+ - invitation
+ - createdAt
+ - metaRetries
+ - self
+ - kind
+ type: object
+ properties:
+ connectionId:
+ type: string
+ description: The unique identifier of the connection.
+ format: uuid
+ example: 0527aea1-d131-3948-a34d-03af39aba8b4
+ thid:
+ type: string
+ description: The unique identifier of the thread this connection record
+ belongs to. The value will identical on both sides of the connection (inviter
+ and invitee)
+ example: 0527aea1-d131-3948-a34d-03af39aba8b4
+ label:
+ type: string
+ description: A human readable alias for the connection.
+ example: Peter
+ goalCode:
+ type: string
+ description: A self-attested code the receiver may want to display to the
+ user or use in automatically deciding what to do with the out-of-band
+ message.
+ example: issue-vc
+ goal:
+ type: string
+ description: A self-attested string that the receiver may want to display
+ to the user about the context-specific goal of the out-of-band message.
+ example: To issue a Peter College Graduate credential
+ myDid:
+ type: string
+ description: The DID representing me as the inviter or invitee in this specific
+ connection.
+ example: did:peer:12345
+ theirDid:
+ type: string
+ description: The DID representing the other peer as the an inviter or invitee
+ in this specific connection.
+ example: did:peer:67890
+ role:
+ type: string
+ description: The role played by the Prism agent in the connection flow.
+ example: Inviter
+ enum:
+ - Inviter
+ - Invitee
+ state:
+ type: string
+ description: The current state of the connection protocol execution.
+ example: InvitationGenerated
+ enum:
+ - InvitationGenerated
+ - InvitationReceived
+ - ConnectionRequestPending
+ - ConnectionRequestSent
+ - ConnectionRequestReceived
+ - ConnectionResponsePending
+ - ConnectionResponseSent
+ - ConnectionResponseReceived
+ - ProblemReportPending
+ - ProblemReportSent
+ - ProblemReportReceived
+ invitation:
+ $ref: '#/components/schemas/ConnectionInvitation'
+ createdAt:
+ type: string
+ description: The date and time the connection record was created.
+ format: date-time
+ example: 2022-03-10T12:00Z
+ updatedAt:
+ type: string
+ description: The date and time the connection record was last updated.
+ format: date-time
+ example: 2022-03-10T12:00Z
+ metaRetries:
+ type: integer
+ description: The maximum background processing attempts remaining for this
+ record
+ format: int32
+ example: 5
+ self:
+ type: string
+ description: The reference to the connection resource.
+ example: https://atala-prism-products.io/connections/ABCD-1234
+ kind:
+ type: string
+ description: The type of object returned. In this case a `Connection`.
+ example: Connection
+ ConnectionInvitation:
+ required:
+ - id
+ - type
+ - from
+ - invitationUrl
+ type: object
+ properties:
+ id:
+ type: string
+ description: The unique identifier of the invitation. It should be used
+ as parent thread ID (pthid) for the Connection Request message that follows.
+ format: uuid
+ example: 0527aea1-d131-3948-a34d-03af39aba8b4
+ type:
+ type: string
+ description: The DIDComm Message Type URI (MTURI) the invitation message
+ complies with.
+ example: https://didcomm.org/out-of-band/2.0/invitation
+ from:
+ type: string
+ description: The DID representing the sender to be used by recipients for
+ future interactions.
+ example: did:peer:1234457
+ invitationUrl:
+ type: string
+ description: The invitation message encoded as a URL. This URL follows the
+ Out of [Band 2.0 protocol](https://identity.foundation/didcomm-messaging/spec/v2.0/#out-of-band-messages)
+ and can be used to generate a QR code for example.
+ example: https://my.domain.com/path?_oob=eyJAaWQiOiIzZmE4NWY2NC01NzE3LTQ1NjItYjNmYy0yYzk2M2Y2NmFmYTYiLCJAdHlwZSI6Imh0dHBzOi8vZGlkY29tbS5vcmcvbXktZmFtaWx5LzEuMC9teS1tZXNzYWdlLXR5cGUiLCJkaWQiOiJXZ1d4cXp0ck5vb0c5MlJYdnhTVFd2IiwiaW1hZ2VVcmwiOiJodHRwOi8vMTkyLjE2OC41Ni4xMDEvaW1nL2xvZ28uanBnIiwibGFiZWwiOiJCb2IiLCJyZWNpcGllbnRLZXlzIjpbIkgzQzJBVnZMTXY2Z21NTmFtM3VWQWpacGZrY0pDd0R3blpuNnozd1htcVBWIl0sInJvdXRpbmdLZXlzIjpbIkgzQzJBVnZMTXY2Z21NTmFtM3VWQWpacGZrY0pDd0R3blpuNnozd1htcVBWIl0sInNlcnZpY2VFbmRwb2ludCI6Imh0dHA6Ly8xOTIuMTY4LjU2LjEwMTo4MDIwIn0=
+ description: The invitation for this connection
+ ConnectionsPage:
+ required:
+ - kind
+ - self
+ - pageOf
+ type: object
+ properties:
+ contents:
+ type: array
+ items:
+ $ref: '#/components/schemas/Connection'
+ description: ''
+ example: []
+ kind:
+ type: string
+ description: ''
+ example: ConnectionsPage
+ self:
+ type: string
+ description: ''
+ example: /prism-agent/connections?offset=10&limit=10
+ pageOf:
+ type: string
+ description: ''
+ example: ''
+ next:
+ type: string
+ description: ''
+ example: /prism-agent/connections?offset=20&limit=10
+ previous:
+ type: string
+ description: ''
+ example: /prism-agent/connections?offset=0&limit=10
+ CreateConnectionRequest:
+ type: object
+ properties:
+ label:
+ type: string
+ description: A human readable alias for the connection.
+ example: Peter
+ goalCode:
+ type: string
+ description: A self-attested code the receiver may want to display to the
+ user or use in automatically deciding what to do with the out-of-band
+ message.
+ example: issue-vc
+ goal:
+ type: string
+ description: A self-attested string that the receiver may want to display
+ to the user about the context-specific goal of the out-of-band message.
+ example: To issue a Peter College Graduate credential
+ CreateEntityRequest:
+ required:
+ - name
+ type: object
+ properties:
+ id:
+ type: string
+ description: The new `id` of the entity to be created. If this field is
+ not provided, the server will generate a new UUID for the entity
+ format: uuid
+ example: 00000000-0000-0000-0000-000000000000
+ name:
+ type: string
+ description: The new `name` of the entity to be created. If this field is
+ not provided, the server will generate a random name for the entity
+ example: John Doe
+ minLength: 1
+ maxLength: 128
+ walletId:
+ type: string
+ description: The new `walletId` of the entity to be created. If this field
+ is not provided, the server will set the default `walletId`
+ format: uuid
+ example: 00000000-0000-0000-0000-000000000000
+ CreateIssueCredentialRecordRequest:
+ required:
+ - claims
+ - connectionId
+ type: object
+ properties:
+ validityPeriod:
+ type: number
+ description: The validity period in seconds of the verifiable credential
+ that will be issued.
+ format: double
+ example: 3600.0
+ schemaId:
+ type: string
+ description: The unique identifier of the schema used for this credential
+ offer.
+ example: https://agent-host.com/prism-agent/schema-registry/schemas/d9569cec-c81e-4779-aa86-0d5994d82676
+ credentialDefinitionId:
+ type: string
+ description: The unique identifier of the credential definition used for
+ this credential offer (AnonCreds only)
+ format: uuid
+ example: d9569cec-c81e-4779-aa86-0d5994d82676
+ credentialFormat:
+ type: string
+ description: The format used for this credential offer (default to 'JWT')
+ example: JWT
+ claims:
+ description: The claims that will be associated with the issued verifiable
+ credential.
+ example: (firstname,Alice)
+ automaticIssuance:
+ type: boolean
+ description: Specifies whether or not the credential should be automatically
+ generated and issued when receiving the `CredentialRequest` from the holder.
+ If set to `false`, a manual approval by the issuer via API call will be
+ required for the VC to be issued.
+ example: true
+ issuingDID:
+ type: string
+ description: The issuer DID of the verifiable credential (JWT credentials
+ only)
+ example: did:prism:issuerofverifiablecredentials
+ connectionId:
+ type: string
+ description: The unique identifier of a DIDComm connection that already
+ exists between the issuer and the holder, and that will be used to execute
+ the issue credential protocol.
+ format: uuid
+ example: d9569cec-c81e-4779-aa86-0d5994d82676
+ CreateManagedDIDResponse:
+ required:
+ - longFormDid
+ type: object
+ properties:
+ longFormDid:
+ type: string
+ description: A long-form DID for the created DID
+ example: did:prism:4a5b5cf0a513e83b598bbea25cd6196746747f361a73ef77068268bc9bd732ff:Cr4BCrsBElsKBmF1dGgtMRAEQk8KCXNlY3AyNTZrMRIg0opTuxu-zt6aRbT1tPniG4eu4CYsQPM3rrLzvzNiNgwaIIFTnyT2N4U7qCQ78qtWC3-p0el6Hvv8qxG5uuEw-WgMElwKB21hc3RlcjAQAUJPCglzZWNwMjU2azESIKhBU0eCOO6Vinz_8vhtFSAhYYqrkEXC8PHGxkuIUev8GiAydFHLXb7c22A1Uj_PR21NZp6BCDQqNq2xd244txRgsQ
+ CreateManagedDidRequest:
+ required:
+ - documentTemplate
+ type: object
+ properties:
+ documentTemplate:
+ $ref: '#/components/schemas/CreateManagedDidRequestDocumentTemplate'
+ CreateManagedDidRequestDocumentTemplate:
+ type: object
+ properties:
+ publicKeys:
+ type: array
+ items:
+ $ref: '#/components/schemas/ManagedDIDKeyTemplate'
+ services:
+ type: array
+ items:
+ $ref: '#/components/schemas/Service'
+ contexts:
+ type: array
+ items:
+ type: string
+ CreateWalletRequest:
+ required:
+ - name
+ type: object
+ properties:
+ seed:
+ type: string
+ description: A BIP32 seed encoded in hexadecimal string. It is expected
+ to represent 64-bytes binary seed (128 hex characters).
+ example: c9994785ce6d548134020f610b76102ca1075d3bb672a75ec8c9a27a7b8607e3b9b384e43b77bb08f8d5159651ae38b98573f7ecc79f2d7e1f1cc371ce60cf8a
+ name:
+ type: string
+ description: A name of the wallet
+ example: my-wallet-1
+ minLength: 1
+ maxLength: 128
+ id:
+ type: string
+ description: The unique `id` of the wallet. Randomly generated if not specified.
+ format: uuid
+ example: 00000000-0000-0000-0000-000000000000
+ CreateWalletUmaPermissionRequest:
+ required:
+ - subject
+ type: object
+ properties:
+ subject:
+ type: string
+ description: The subject ID that should be granted the permission to the
+ wallet. This can be found in the `sub` claim of a JWT token.
+ format: uuid
+ example: 00000000-0000-0000-0000-000000000000
+ CreateWebhookNotification:
+ required:
+ - url
+ type: object
+ properties:
+ url:
+ type: string
+ customHeaders:
+ $ref: '#/components/schemas/Map_String'
+ CredentialDefinitionInput:
+ required:
+ - name
+ - version
+ - tag
+ - author
+ - schemaId
+ - signatureType
+ - supportRevocation
+ type: object
+ properties:
+ name:
+ type: string
+ description: A human-readable name for the credential definition. A piece
+ of Metadata.
+ example: DrivingLicense
+ minLength: 1
+ description:
+ type: string
+ description: A human-readable description of the credential definition
+ example: Simple credential definition for the driving licence verifiable
+ credential.
+ minLength: 1
+ version:
+ type: string
+ description: Denotes the revision of a given Credential Definition. It should
+ follow semantic version convention to describe the impact of the credential
+ definition evolution.
+ example: 1.0.0
+ pattern: ^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$
+ tag:
+ type: string
+ description: Token that allow to lookup and filter the credential definition
+ records.
+ example: licence
+ author:
+ type: string
+ description: DID of the identity which authored the credential definition.
+ A piece of Metadata.
+ example: did:prism:4a5b5cf0a513e83b598bbea25cd6196746747f361a73ef77068268bc9bd732ff
+ pattern: ^did:(?[a-z0-9]+(:[a-z0-9]+)*)\:(?[^#?]*)$
+ schemaId:
+ type: string
+ description: The unique identifier of the schema used for this credential
+ definition.
+ example: https://agent-host.com/prism-agent/schema-registry/schemas/d9569cec-c81e-4779-aa86-0d5994d82676
+ signatureType:
+ type: string
+ description: Signature type used in the CredentialDefinition.
+ example: CL
+ supportRevocation:
+ type: boolean
+ description: Boolean flag indicating whether revocation is supported for
+ this CredentialDefinition.
+ example: false
+ CredentialDefinitionResponse:
+ required:
+ - guid
+ - id
+ - name
+ - version
+ - tag
+ - description
+ - author
+ - authored
+ - schemaId
+ - definition
+ - keyCorrectnessProof
+ - signatureType
+ - supportRevocation
+ - kind
+ - self
+ type: object
+ properties:
+ guid:
+ type: string
+ description: 'Globally unique id of the credential definition.It''s composed
+ from the bytes of the string that contain the `author`, `name`, and `version`
+ values.The string format looks like the resource identifier: `author`/`id`?version=`version`'
+ format: uuid
+ example: 0527aea1-d131-3948-a34d-03af39aba8b4
+ id:
+ type: string
+ description: A locally unique identifier to address the credential definition.
+ UUID is generated by the backend.
+ example: 0527aea1-d131-3948-a34d-03af39aba8b5
+ longId:
+ type: string
+ description: Resource id of the credential definition. Contains the `author`'s
+ DID, `id` and `version` fields.
+ example: did:prism:4a5b5cf0a513e83b598bbea25cd6196746747f361a73ef77068268bc9bd732ff/0527aea1-d131-3948-a34d-03af39aba8b4?version=1.0.0
+ name:
+ type: string
+ description: A human-readable name for the credential definition. A piece
+ of Metadata.
+ example: DrivingLicense
+ version:
+ type: string
+ description: Denotes the revision of a given Credential Definition. It should
+ follow semantic version convention to describe the impact of the credential
+ definition evolution.
+ example: 1.0.0
+ tag:
+ type: string
+ description: Token that allow to lookup and filter the credential definition
+ records.
+ example: licence
+ description:
+ type: string
+ description: A human-readable description of the credential definition
+ example: Simple credential definition for the driving licence verifiable
+ credential.
+ author:
+ type: string
+ description: DID of the identity which authored the credential definition.
+ A piece of Metadata.
+ example: did:prism:4a5b5cf0a513e83b598bbea25cd6196746747f361a73ef77068268bc9bd732ff
+ authored:
+ type: string
+ description: '[RFC3339](https://www.rfc-editor.org/rfc/rfc3339) date on
+ which the credential definition was created. A piece of Metadata.'
+ format: date-time
+ example: 2022-03-10T12:00Z
+ schemaId:
+ type: string
+ description: The unique identifier of the schema used for this credential
+ definition.
+ example: https://agent-host.com/prism-agent/schema-registry/schemas/d9569cec-c81e-4779-aa86-0d5994d82676
+ definition:
+ description: Definition object that represents the actual definition of
+ the credential.
+ example:
+ credentialSubject:
+ emailAddress: alice@wonderland.com
+ givenName: Alice
+ familyName: Wonderland
+ dateOfIssuance: '2000-01-01T10:00:00Z'
+ drivingLicenseID: '12345'
+ drivingClass: 5
+ keyCorrectnessProof:
+ description: A proof that validates the correctness of the key within the
+ context of the credential definition.
+ signatureType:
+ type: string
+ description: Signature type used in the CredentialDefinition.
+ example: CL
+ supportRevocation:
+ type: boolean
+ description: Boolean flag indicating whether revocation is supported for
+ this CredentialDefinition.
+ example: false
+ proof:
+ $ref: '#/components/schemas/Proof'
+ kind:
+ type: string
+ description: A string that identifies the type of resource being returned
+ in the response.
+ example: CredentialDefinition
+ self:
+ type: string
+ description: The URL that uniquely identifies the resource being returned
+ in the response.
+ example: /prism-agent/credential-definition-registry/schemas/0527aea1-d131-3948-a34d-03af39aba8b4
+ CredentialDefinitionResponsePage:
+ required:
+ - kind
+ - self
+ - pageOf
+ type: object
+ properties:
+ contents:
+ type: array
+ items:
+ $ref: '#/components/schemas/CredentialDefinitionResponse'
+ description: A sequence of CredentialSchemaResponse objects representing
+ the list of credential schemas that the API response contains
+ example: []
+ kind:
+ type: string
+ description: A string field indicating the type of the API response. In
+ this case, it will always be set to `CredentialSchemaPage`
+ example: CredentialSchemaPage
+ self:
+ type: string
+ description: A string field containing the URL of the current API endpoint
+ example: /prism-agent/schema-registry/schemas?skip=10&limit=10
+ pageOf:
+ type: string
+ description: A string field indicating the type of resource that the contents
+ field contains
+ example: /prism-agent/schema-registry/schemas
+ next:
+ type: string
+ description: An optional string field containing the URL of the next page
+ of results. If the API response does not contain any more pages, this
+ field should be set to None.
+ example: /prism-agent/schema-registry/schemas?skip=20&limit=10
+ previous:
+ type: string
+ description: An optional string field containing the URL of the previous
+ page of results. If the API response is the first page of results, this
+ field should be set to None.
+ example: /prism-agent/schema-registry/schemas?skip=0&limit=10
+ CredentialSchemaInput:
+ required:
+ - name
+ - version
+ - type
+ - schema
+ - author
+ type: object
+ properties:
+ name:
+ type: string
+ description: A human-readable name for the credential schema. A piece of
+ Metadata.
+ example: DrivingLicense
+ minLength: 1
+ version:
+ type: string
+ description: Denotes the revision of a given Credential Schema. It should
+ follow semantic version convention to describe the impact of the schema
+ evolution.
+ example: 1.0.0
+ pattern: ^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$
+ description:
+ type: string
+ description: A human-readable description of the credential schema
+ example: Simple credential schema for the driving licence verifiable credential.
+ minLength: 1
+ type:
+ type: string
+ description: This field resolves to a JSON schema with details about the
+ schema metadata that applies to the schema. A piece of Metadata.
+ example: https://w3c-ccg.github.io/vc-json-schemas/schema/2.0/schema.json
+ schema:
+ description: Valid JSON Schema where the Credential Schema data fields are
+ defined. A piece of Metadata
+ example:
+ $id: https://example.com/driving-license-1.0
+ $schema: https://json-schema.org/draft/2020-12/schema
+ description: Driving License
+ type: object
+ properties:
+ emailAddress:
+ type: string
+ format: email
+ givenName:
+ type: string
+ familyName:
+ type: string
+ dateOfIssuance:
+ type: string
+ format: date-time
+ drivingLicenseID:
+ type: string
+ drivingClass:
+ type: integer
+ required:
+ - emailAddress
+ - familyName
+ - dateOfIssuance
+ - drivingLicenseID
+ - drivingClass
+ additionalProperties: false
+ tags:
+ type: array
+ items:
+ type: string
+ description: Tokens that allow to lookup and filter the credential schema
+ records.
+ example:
+ - driving
+ - licence
+ - id
+ author:
+ type: string
+ description: DID of the identity which authored the credential schema. A
+ piece of Metadata.
+ example: did:prism:4a5b5cf0a513e83b598bbea25cd6196746747f361a73ef77068268bc9bd732ff
+ pattern: ^did:(?[a-z0-9]+(:[a-z0-9]+)*)\:(?[^#?]*)$
+ CredentialSchemaResponse:
+ required:
+ - guid
+ - id
+ - name
+ - version
+ - description
+ - type
+ - schema
+ - author
+ - authored
+ - kind
+ - self
+ type: object
+ properties:
+ guid:
+ type: string
+ description: 'Globally unique id of the credential schema.It''s composed
+ from the bytes of the string that contain the `author`, `name`, and `version`
+ values.The string format looks like the resource identifier: `author`/`id`?version=`version`'
+ format: uuid
+ example: 0527aea1-d131-3948-a34d-03af39aba8b4
+ id:
+ type: string
+ description: A locally unique identifier to address the schema. UUID is
+ generated by the backend.
+ example: 0527aea1-d131-3948-a34d-03af39aba8b5
+ longId:
+ type: string
+ description: Resource id of the credential schema. Contains the `author`'s
+ DID, `id` and `version` fields.
+ example: did:prism:4a5b5cf0a513e83b598bbea25cd6196746747f361a73ef77068268bc9bd732ff/0527aea1-d131-3948-a34d-03af39aba8b4?version=1.0.0
+ name:
+ type: string
+ description: A human-readable name for the credential schema. A piece of
+ Metadata.
+ example: DrivingLicense
+ version:
+ type: string
+ description: Denotes the revision of a given Credential Schema. It should
+ follow semantic version convention to describe the impact of the schema
+ evolution.
+ example: 1.0.0
+ tags:
+ type: array
+ items:
+ type: string
+ description: Tokens that allow to lookup and filter the credential schema
+ records.
+ example:
+ - driving
+ - licence
+ - id
+ description:
+ type: string
+ description: A human-readable description of the credential schema
+ example: Simple credential schema for the driving licence verifiable credential.
+ type:
+ type: string
+ description: This field resolves to a JSON schema with details about the
+ schema metadata that applies to the schema. A piece of Metadata.
+ example: https://w3c-ccg.github.io/vc-json-schemas/schema/2.0/schema.json
+ schema:
+ description: Valid JSON Schema where the Credential Schema data fields are
+ defined. A piece of Metadata
+ example:
+ $id: https://example.com/driving-license-1.0
+ $schema: https://json-schema.org/draft/2020-12/schema
+ description: Driving License
+ type: object
+ properties:
+ emailAddress:
+ type: string
+ format: email
+ givenName:
+ type: string
+ familyName:
+ type: string
+ dateOfIssuance:
+ type: string
+ format: date-time
+ drivingLicenseID:
+ type: string
+ drivingClass:
+ type: integer
+ required:
+ - emailAddress
+ - familyName
+ - dateOfIssuance
+ - drivingLicenseID
+ - drivingClass
+ additionalProperties: false
+ author:
+ type: string
+ description: DID of the identity which authored the credential schema. A
+ piece of Metadata.
+ example: did:prism:4a5b5cf0a513e83b598bbea25cd6196746747f361a73ef77068268bc9bd732ff
+ authored:
+ type: string
+ description: '[RFC3339](https://www.rfc-editor.org/rfc/rfc3339) date on
+ which the credential schema was created. A piece of Metadata.'
+ format: date-time
+ example: 2022-03-10T12:00Z
+ proof:
+ $ref: '#/components/schemas/Proof1'
+ kind:
+ type: string
+ description: A string that identifies the type of resource being returned
+ in the response.
+ example: CredentialSchema
+ self:
+ type: string
+ description: The URL that uniquely identifies the resource being returned
+ in the response.
+ example: /prism-agent/schema-registry/schemas/0527aea1-d131-3948-a34d-03af39aba8b4
+ CredentialSchemaResponsePage:
+ required:
+ - kind
+ - self
+ - pageOf
+ type: object
+ properties:
+ contents:
+ type: array
+ items:
+ $ref: '#/components/schemas/CredentialSchemaResponse'
+ description: A sequence of CredentialSchemaResponse objects representing
+ the list of credential schemas that the API response contains
+ example: []
+ kind:
+ type: string
+ description: A string field indicating the type of the API response. In
+ this case, it will always be set to `CredentialSchemaPage`
+ example: CredentialSchemaPage
+ self:
+ type: string
+ description: A string field containing the URL of the current API endpoint
+ example: /prism-agent/schema-registry/schemas?skip=10&limit=10
+ pageOf:
+ type: string
+ description: A string field indicating the type of resource that the contents
+ field contains
+ example: /prism-agent/schema-registry/schemas
+ next:
+ type: string
+ description: An optional string field containing the URL of the next page
+ of results. If the API response does not contain any more pages, this
+ field should be set to None.
+ example: /prism-agent/schema-registry/schemas?skip=20&limit=10
+ previous:
+ type: string
+ description: An optional string field containing the URL of the previous
+ page of results. If the API response is the first page of results, this
+ field should be set to None.
+ example: /prism-agent/schema-registry/schemas?skip=0&limit=10
+ DIDDocument:
+ required:
+ - id
+ type: object
+ properties:
+ '@context':
+ type: array
+ items:
+ type: string
+ description: The JSON-LD context for the DID resolution result.
+ id:
+ type: string
+ description: |-
+ [DID subject](https://www.w3.org/TR/did-core/#did-subject).
+ The value must match the DID that was given to the resolver.
+ example: did:prism:4a5b5cf0a513e83b598bbea25cd6196746747f361a73ef77068268bc9bd732ff
+ controller:
+ type: string
+ description: '[DID controller](https://www.w3.org/TR/did-core/#did-controller)'
+ example: did:prism:4a5b5cf0a513e83b598bbea25cd6196746747f361a73ef77068268bc9bd732ff
+ verificationMethod:
+ type: array
+ items:
+ $ref: '#/components/schemas/VerificationMethod'
+ authentication:
+ type: array
+ items:
+ type: string
+ assertionMethod:
+ type: array
+ items:
+ type: string
+ keyAgreement:
+ type: array
+ items:
+ type: string
+ capabilityInvocation:
+ type: array
+ items:
+ type: string
+ capabilityDelegation:
+ type: array
+ items:
+ type: string
+ service:
+ type: array
+ items:
+ $ref: '#/components/schemas/Service'
+ description: A W3C compliant Prism DID document representation.
+ DIDDocumentMetadata:
+ type: object
+ properties:
+ deactivated:
+ type: boolean
+ description: If a DID has been deactivated, DID document metadata MUST include
+ this property with the boolean value true. If a DID has not been deactivated,
+ this property is OPTIONAL, but if included, MUST have the boolean value
+ false.
+ example: false
+ canonicalId:
+ type: string
+ description: |2
+
+ A DID in canonical form.
+ If a DID is in long form and has been published, DID document metadata MUST contain a `canonicalId`` property with the short form DID as its value.
+ If a DID in short form or has not been published, DID document metadata MUST NOT contain a `canonicalId` property.
+ example: did:prism:4a5b5cf0a513e83b598bbea25cd6196746747f361a73ef77068268bc9bd732ff
+ versionId:
+ type: string
+ description: |2
+
+ DID document metadata MUST contain a versionId property with the hash of the AtalaOperation contained in the latest valid SignedAtalaOperation that created the DID or changed the DID's internal state.
+ example: 4a5b5cf0a513e83b598bbea25cd6196746747f361a73ef77068268bc9bd732ff
+ created:
+ type: string
+ description: The timestamp of the Cardano block that contained the first
+ valid SignedAtalaOperation with a CreateDIDOperation that created the
+ DID.
+ example: '2023-02-04T13:52:10Z'
+ updated:
+ type: string
+ description: The timestamp of the Cardano block that contained the latest
+ valid SignedAtalaOperation that changed the DID's internal state.
+ example: '2023-02-04T13:52:10Z'
+ description: '[DID document metadata](https://www.w3.org/TR/did-core/#did-document-metadata)'
+ DIDOperationResponse:
+ required:
+ - scheduledOperation
+ type: object
+ properties:
+ scheduledOperation:
+ $ref: '#/components/schemas/DidOperationSubmission'
+ DIDResolutionMetadata:
+ type: object
+ properties:
+ error:
+ type: string
+ description: Resolution error constant according to [DID spec registries](https://www.w3.org/TR/did-spec-registries/#error)
+ example: invalidDid
+ errorMessage:
+ type: string
+ description: Resolution error message
+ example: The initialState does not match the suffix
+ contentType:
+ type: string
+ description: The media type of the returned DID document
+ example: application/did+ld+json
+ description: '[DID resolution metadata](https://www.w3.org/TR/did-core/#did-resolution-metadata)'
+ DIDResolutionResult:
+ required:
+ - '@context'
+ - didDocumentMetadata
+ - didResolutionMetadata
+ type: object
+ properties:
+ '@context':
+ type: string
+ description: The JSON-LD context for the DID resolution result.
+ example: https://w3id.org/did-resolution/v1
+ didDocument:
+ $ref: '#/components/schemas/DIDDocument'
+ didDocumentMetadata:
+ $ref: '#/components/schemas/DIDDocumentMetadata'
+ didResolutionMetadata:
+ $ref: '#/components/schemas/DIDResolutionMetadata'
+ DidOperationSubmission:
+ required:
+ - id
+ - didRef
+ type: object
+ properties:
+ id:
+ type: string
+ description: A scheduled operation ID
+ example: 98e6a4db10e58fcc011dd8def5ce99fd8b52af39e61e5fb436dc28259139818b
+ didRef:
+ type: string
+ description: A DID affected by the scheduled operation
+ example: did:prism:4a5b5cf0a513e83b598bbea25cd6196746747f361a73ef77068268bc9bd732ff
+ EntityResponse:
+ required:
+ - kind
+ - self
+ - id
+ - name
+ - walletId
+ - createdAt
+ - updatedAt
+ type: object
+ properties:
+ kind:
+ type: string
+ description: The `kind` of the entity.
+ example: Entity
+ self:
+ type: string
+ description: The `self` link of the entity.
+ example: http://localhost:8080/prism-agent/iam/entities/00000000-0000-0000-0000-000000000000
+ id:
+ type: string
+ description: The unique `id` of the entity
+ format: uuid
+ example: 00000000-0000-0000-0000-000000000000
+ name:
+ type: string
+ description: The `name` of the entity.
+ example: John Doe
+ walletId:
+ type: string
+ description: The `walletId` owned by the entity.
+ format: uuid
+ example: 00000000-0000-0000-0000-000000000000
+ createdAt:
+ type: string
+ description: The `createdAt` timestamp of the entity.
+ format: date-time
+ example: '2023-01-01T00:00:00Z'
+ updatedAt:
+ type: string
+ description: The `updatedAt` timestamp of the entity.
+ format: date-time
+ example: '2023-01-01T00:00:00Z'
+ EntityResponsePage:
+ required:
+ - kind
+ - self
+ - pageOf
+ type: object
+ properties:
+ contents:
+ type: array
+ items:
+ $ref: '#/components/schemas/EntityResponse'
+ description: A sequence of CredentialSchemaResponse objects representing
+ the list of credential schemas that the API response contains
+ example:
+ - EntityResponse(Entity,/prism-agent/iam/entities/00000000-0000-0000-0000-000000000000,00000000-0000-0000-0000-000000000000,John
+ Doe,00000000-0000-0000-0000-000000000000,2023-01-01T00:00:00Z,2023-01-01T00:00:00Z)
+ kind:
+ type: string
+ description: A string field indicating the type of the API response. In
+ this case, it will always be set to `CredentialSchemaPage`
+ example: CredentialSchemaPage
+ self:
+ type: string
+ description: A string field containing the URL of the current API endpoint
+ example: /prism-agent/schema-registry/schemas?skip=10&limit=10
+ pageOf:
+ type: string
+ description: A string field indicating the type of resource that the contents
+ field contains
+ example: /prism-agent/schema-registry/schemas
+ next:
+ type: string
+ description: An optional string field containing the URL of the next page
+ of results. If the API response does not contain any more pages, this
+ field should be set to None.
+ example: /prism-agent/schema-registry/schemas?skip=20&limit=10
+ previous:
+ type: string
+ description: An optional string field containing the URL of the previous
+ page of results. If the API response is the first page of results, this
+ field should be set to None.
+ example: /prism-agent/schema-registry/schemas?skip=0&limit=10
+ ErrorResponse:
+ required:
+ - status
+ - type
+ - title
+ - instance
+ type: object
+ properties:
+ status:
+ type: integer
+ description: The HTTP status code for this occurrence of the problem.
+ format: int32
+ example: 200
+ type:
+ type: string
+ description: A URI reference that identifies the problem type.
+ example: https://example.org/doc/#model-MalformedEmail/
+ title:
+ type: string
+ description: A short, human-readable summary of the problem type. It does
+ not change from occurrence to occurrence of the problem.
+ example: Malformed email
+ detail:
+ type: string
+ description: A human-readable explanation specific to this occurrence of
+ the problem.
+ example: The received '{}à!è@!.b}' email does not conform to the email format
+ instance:
+ type: string
+ description: A URI reference that identifies the specific occurrence of
+ the problem. It may or may not yield further information if dereferenced.
+ example: The received '{}à!è@!.b}' email does not conform to the email format
+ HealthInfo:
+ required:
+ - version
+ type: object
+ properties:
+ version:
+ type: string
+ description: The semantic version number of the running service
+ example: 1.1.0
+ IssueCredentialRecord:
+ required:
+ - recordId
+ - thid
+ - credentialFormat
+ - claims
+ - createdAt
+ - role
+ - protocolState
+ - metaRetries
+ type: object
+ properties:
+ recordId:
+ type: string
+ description: The unique identifier of the issue credential record.
+ example: 80d612dc-0ded-4ac9-90b4-1b8eabb04545
+ thid:
+ type: string
+ description: The unique identifier of the thread this credential record
+ belongs to. The value will identical on both sides of the issue flow (issuer
+ and holder)
+ example: 0527aea1-d131-3948-a34d-03af39aba8b4
+ credentialFormat:
+ type: string
+ description: The format used for this credential offer (default to 'JWT')
+ example: JWT
+ enum:
+ - JWT
+ - AnonCreds
+ subjectId:
+ type: string
+ description: The identifier (e.g DID) of the subject to which the verifiable
+ credential will be issued.
+ example: did:prism:subjectofverifiablecredentials
+ validityPeriod:
+ type: number
+ description: The validity period in seconds of the verifiable credential
+ that will be issued.
+ format: double
+ example: 3600.0
+ claims:
+ description: The claims that will be associated with the issued verifiable
+ credential.
+ example: (firstname,Alice)
+ automaticIssuance:
+ type: boolean
+ description: Specifies whether or not the credential should be automatically
+ generated and issued when receiving the `CredentialRequest` from the holder.
+ If set to `false`, a manual approval by the issuer via API call will be
+ required for the VC to be issued.
+ example: true
+ createdAt:
+ type: string
+ description: The date and time when the issue credential record was created.
+ format: date-time
+ example: '2023-12-06T10:40:43.781066302Z'
+ updatedAt:
+ type: string
+ description: The date and time when the issue credential record was last
+ updated.
+ format: date-time
+ role:
+ type: string
+ description: The role played by the Prism agent in the credential issuance
+ flow.
+ example: Issuer
+ enum:
+ - Issuer
+ - Holder
+ protocolState:
+ type: string
+ description: The current state of the issue credential protocol execution.
+ example: OfferPending
+ enum:
+ - OfferPending
+ - OfferSent
+ - OfferReceived
+ - RequestPending
+ - RequestGenerated
+ - RequestSent
+ - RequestReceived
+ - CredentialPending
+ - CredentialGenerated
+ - CredentialSent
+ - CredentialReceived
+ - ProblemReportPending
+ - ProblemReportSent
+ - ProblemReportReceived
+ credential:
+ type: string
+ description: The base64-encoded verifiable credential, in JWT or AnonCreds
+ format, that has been sent by the issuer.
+ issuingDID:
+ type: string
+ description: Issuer DID of the verifiable credential object.
+ example: did:prism:issuerofverifiablecredentials
+ metaRetries:
+ type: integer
+ description: The maximum background processing attempts remaining for this
+ record
+ format: int32
+ example: 5
+ IssueCredentialRecordPage:
+ required:
+ - self
+ - kind
+ - pageOf
+ type: object
+ properties:
+ self:
+ type: string
+ description: A string field containing the URL of the current API endpoint
+ example: /prism-agent/schema-registry/schemas?skip=10&limit=10
+ kind:
+ type: string
+ description: A string field containing the URL of the current API endpoint
+ example: /prism-agent/schema-registry/schemas?skip=10&limit=10
+ pageOf:
+ type: string
+ description: A string field indicating the type of resource that the contents
+ field contains
+ example: /prism-agent/schema-registry/schemas
+ next:
+ type: string
+ description: An optional string field containing the URL of the next page
+ of results. If the API response does not contain any more pages, this
+ field should be set to None.
+ example: /prism-agent/schema-registry/schemas?skip=20&limit=10
+ previous:
+ type: string
+ description: An optional string field containing the URL of the previous
+ page of results. If the API response is the first page of results, this
+ field should be set to None.
+ example: /prism-agent/schema-registry/schemas?skip=0&limit=10
+ contents:
+ type: array
+ items:
+ $ref: '#/components/schemas/IssueCredentialRecord'
+ description: A sequence of IssueCredentialRecord objects representing the
+ list of credential records that the API response contains
+ example: []
+ Json:
+ description: The service endpoint. Can contain multiple possible values as described
+ in the [Create DID operation]
+ example: https://example.com
+ oneOf:
+ - $ref: '#/components/schemas/Arr'
+ - $ref: '#/components/schemas/Bool'
+ - $ref: '#/components/schemas/Null'
+ - $ref: '#/components/schemas/Num'
+ - $ref: '#/components/schemas/Obj'
+ - $ref: '#/components/schemas/Str'
+ ManagedDID:
+ required:
+ - did
+ - status
+ type: object
+ properties:
+ did:
+ type: string
+ description: A managed DID
+ example: did:prism:4a5b5cf0a513e83b598bbea25cd6196746747f361a73ef77068268bc9bd732ff
+ longFormDid:
+ type: string
+ description: A long-form DID. Mandatory when status is not PUBLISHED and
+ optional when status is PUBLISHED
+ example: did:prism:4a5b5cf0a513e83b598bbea25cd6196746747f361a73ef77068268bc9bd732ff:Cr4BCrsBElsKBmF1dGgtMRAEQk8KCXNlY3AyNTZrMRIg0opTuxu-zt6aRbT1tPniG4eu4CYsQPM3rrLzvzNiNgwaIIFTnyT2N4U7qCQ78qtWC3-p0el6Hvv8qxG5uuEw-WgMElwKB21hc3RlcjAQAUJPCglzZWNwMjU2azESIKhBU0eCOO6Vinz_8vhtFSAhYYqrkEXC8PHGxkuIUev8GiAydFHLXb7c22A1Uj_PR21NZp6BCDQqNq2xd244txRgsQ
+ status:
+ type: string
+ description: |-
+ A status indicating a publication state of a DID in the wallet (e.g. PUBLICATION_PENDING, PUBLISHED).
+ Does not represent DID a full lifecyle (e.g. deactivated, recovered, updated).
+ example: CREATED
+ ManagedDIDKeyTemplate:
+ required:
+ - id
+ - purpose
+ type: object
+ properties:
+ id:
+ type: string
+ description: Identifier of a verification material in the DID Document
+ example: key-1
+ purpose:
+ $ref: '#/components/schemas/Purpose'
+ description: key-pair template to add to DID document.
+ ManagedDIDPage:
+ required:
+ - self
+ - kind
+ - pageOf
+ type: object
+ properties:
+ self:
+ type: string
+ kind:
+ type: string
+ pageOf:
+ type: string
+ next:
+ type: string
+ previous:
+ type: string
+ contents:
+ type: array
+ items:
+ $ref: '#/components/schemas/ManagedDID'
+ Map_String:
+ type: object
+ additionalProperties:
+ type: string
+ 'Null':
+ type: object
+ Num:
+ required:
+ - value
+ type: object
+ properties:
+ value:
+ type: number
+ Obj:
+ type: object
+ Options:
+ required:
+ - challenge
+ - domain
+ type: object
+ properties:
+ challenge:
+ type: string
+ description: The challenge should be a randomly generated string.
+ example: 11c91493-01b3-4c4d-ac36-b336bab5bddf
+ domain:
+ type: string
+ description: The domain value can be any string or URI.
+ example: https://example-verifier.com
+ description: The options to use when creating the proof presentation request
+ (e.g., domain, challenge).
+ PatchContextAction:
+ type: object
+ properties:
+ contexts:
+ type: array
+ items:
+ type: string
+ PresentationStatus:
+ required:
+ - presentationId
+ - thid
+ - role
+ - status
+ - metaRetries
+ type: object
+ properties:
+ presentationId:
+ type: string
+ description: The unique identifier of the presentation record.
+ example: 3c6d9fa5-d277-431e-a6cb-d3956e47e610
+ thid:
+ type: string
+ description: The unique identifier of the thread this presentation record
+ belongs to. The value will identical on both sides of the presentation
+ flow (verifier and prover)
+ example: 0527aea1-d131-3948-a34d-03af39aba8b4
+ role:
+ type: string
+ description: The role played by the Prism agent in the proof presentation
+ flow.
+ example: Verifier
+ enum:
+ - Verifier
+ - Prover
+ status:
+ type: string
+ description: The current state of the proof presentation record.
+ example: RequestPending
+ enum:
+ - RequestPending
+ - RequestSent
+ - RequestReceived
+ - RequestRejected
+ - PresentationPending
+ - PresentationGenerated
+ - PresentationSent
+ - PresentationReceived
+ - PresentationVerified
+ - PresentationAccepted
+ - PresentationRejected
+ - ProblemReportPending
+ - ProblemReportSent
+ - ProblemReportReceived
+ proofs:
+ type: array
+ items:
+ $ref: '#/components/schemas/ProofRequestAux'
+ description: The type of proofs requested in the context of this proof presentation
+ request (e.g., VC schema, trusted issuers, etc.)
+ example: []
+ data:
+ type: array
+ items:
+ type: string
+ description: The list of proofs presented by the prover to the verifier.
+ example: []
+ connectionId:
+ type: string
+ description: The unique identifier of an established connection between
+ the verifier and the prover.
+ example: bc528dc8-69f1-4c5a-a508-5f8019047900
+ metaRetries:
+ type: integer
+ description: The maximum background processing attempts remaining for this
+ record
+ format: int32
+ example: 5
+ PresentationStatusPage:
+ required:
+ - self
+ - kind
+ - pageOf
+ type: object
+ properties:
+ contents:
+ type: array
+ items:
+ $ref: '#/components/schemas/PresentationStatus'
+ description: A sequence of Presentation objects.
+ example: []
+ self:
+ type: string
+ description: The reference to the presentation collection itself.
+ example: /present-proof/presentations
+ kind:
+ type: string
+ description: The type of object returned. In this case a `Collection`.
+ example: Collection
+ pageOf:
+ type: string
+ description: Page number within the context of paginated response.
+ example: 1
+ next:
+ type: string
+ description: URL of the next page (if available)
+ example: ''
+ previous:
+ type: string
+ description: URL of the previous page (if available)
+ example: ''
+ Proof:
+ required:
+ - type
+ - created
+ - verificationMethod
+ - proofPurpose
+ - proofValue
+ - jws
+ type: object
+ properties:
+ type:
+ type: string
+ description: The type of cryptographic signature algorithm used to generate
+ the proof.
+ example: Ed25519Signature2018
+ created:
+ type: string
+ description: The date and time at which the proof was created, in UTC format.
+ This field is used to ensure that the proof was generated before or at
+ the same time as the credential definition itself.
+ format: date-time
+ example: 2022-03-10T12:00Z
+ verificationMethod:
+ type: string
+ description: The verification method used to generate the proof. This is
+ usually a DID and key ID combination that can be used to look up the public
+ key needed to verify the proof.
+ example: did:prism:4a5b5cf0a513e83b598bbea25cd6196746747f361a73ef77068268bc9bd732ff#key-1
+ proofPurpose:
+ type: string
+ description: 'The purpose of the proof (for example: `assertionMethod`).
+ This indicates that the proof is being used to assert that the issuer
+ really issued this credential definition instance.'
+ example: assertionMethod
+ proofValue:
+ type: string
+ description: The cryptographic signature value that was generated using
+ the private key associated with the verification method, and which can
+ be used to verify the proof.
+ example: FiPfjknHikKmZ...
+ jws:
+ type: string
+ description: The JSON Web Signature (JWS) that contains the proof information.
+ example: eyJhbGciOiJFZERTQSIsImI2NCI6ZmFsc2UsImNyaXQiOlsiYjY0Il0sImt0eSI6Ik...
+ domain:
+ type: string
+ description: It specifies the domain context within which the credential
+ definition and proof are being used
+ example: prims.atala.com
+ description: A digital signature over the Credential Definition for the sake
+ of asserting authorship. A piece of Metadata.
+ example:
+ type: Ed25519Signature2018
+ created: '2022-03-10T12:00:00Z'
+ verificationMethod: did:prism:4a5b5cf0a513e83b598bbea25cd6196746747f361a73ef77068268bc9bd732ff#key-1
+ proofPurpose: assertionMethod
+ proofValue: FiPfjknHikKmZ...
+ jws: eyJhbGciOiJFZERTQSIsImI2NCI6ZmFsc2UsImNyaXQiOlsiYjY0Il0sImt0eSI6Ik...
+ domain: prims.atala.com
+ Proof1:
+ required:
+ - type
+ - created
+ - verificationMethod
+ - proofPurpose
+ - proofValue
+ - jws
+ type: object
+ properties:
+ type:
+ type: string
+ description: The type of cryptographic signature algorithm used to generate
+ the proof.
+ example: Ed25519Signature2018
+ created:
+ type: string
+ description: The date and time at which the proof was created, in UTC format.
+ This field is used to ensure that the proof was generated before or at
+ the same time as the credential schema itself.
+ format: date-time
+ example: 2022-03-10T12:00Z
+ verificationMethod:
+ type: string
+ description: The verification method used to generate the proof. This is
+ usually a DID and key ID combination that can be used to look up the public
+ key needed to verify the proof.
+ example: did:prism:4a5b5cf0a513e83b598bbea25cd6196746747f361a73ef77068268bc9bd732ff#key-1
+ proofPurpose:
+ type: string
+ description: 'The purpose of the proof (for example: `assertionMethod`).
+ This indicates that the proof is being used to assert that the issuer
+ really issued this credential schema instance.'
+ example: assertionMethod
+ proofValue:
+ type: string
+ description: The cryptographic signature value that was generated using
+ the private key associated with the verification method, and which can
+ be used to verify the proof.
+ example: FiPfjknHikKmZ...
+ jws:
+ type: string
+ description: The JSON Web Signature (JWS) that contains the proof information.
+ example: eyJhbGciOiJFZERTQSIsImI2NCI6ZmFsc2UsImNyaXQiOlsiYjY0Il0sImt0eSI6Ik...
+ domain:
+ type: string
+ description: It specifies the domain context within which the credential
+ schema and proof are being used
+ example: prims.atala.com
+ description: A digital signature over the Credential Schema for the sake of
+ asserting authorship. A piece of Metadata.
+ example:
+ type: Ed25519Signature2018
+ created: '2022-03-10T12:00:00Z'
+ verificationMethod: did:prism:4a5b5cf0a513e83b598bbea25cd6196746747f361a73ef77068268bc9bd732ff#key-1
+ proofPurpose: assertionMethod
+ proofValue: FiPfjknHikKmZ...
+ jws: eyJhbGciOiJFZERTQSIsImI2NCI6ZmFsc2UsImNyaXQiOlsiYjY0Il0sImt0eSI6Ik...
+ domain: prims.atala.com
+ ProofRequestAux:
+ required:
+ - schemaId
+ type: object
+ properties:
+ schemaId:
+ type: string
+ description: The unique identifier of a schema the VC should comply with.
+ example: https://schema.org/Person
+ trustIssuers:
+ type: array
+ items:
+ type: string
+ description: One or more issuers that are trusted by the verifier emitting
+ the proof presentation request.
+ example:
+ - did:web:atalaprism.io/users/testUser
+ - did.prism:123
+ - did:prism:...
+ PublicKeyJwk:
+ required:
+ - kty
+ type: object
+ properties:
+ crv:
+ type: string
+ x:
+ type: string
+ y:
+ type: string
+ kty:
+ type: string
+ Purpose:
+ type: string
+ description: Purpose of the verification material in the DID Document
+ example: authentication
+ enum:
+ - assertionMethod
+ - authentication
+ - capabilityDelegation
+ - capabilityInvocation
+ - keyAgreement
+ RemoveEntryById:
+ required:
+ - id
+ type: object
+ properties:
+ id:
+ type: string
+ RequestPresentationAction:
+ required:
+ - action
+ type: object
+ properties:
+ action:
+ type: string
+ description: The action to perform on the proof presentation record.
+ example: request-accept
+ enum:
+ - request-accept
+ - request-reject
+ - presentation-accept
+ - presentation-reject
+ proofId:
+ type: array
+ items:
+ type: string
+ description: The unique identifier of the issue credential record - and
+ hence VC - to use as the prover accepts the presentation request. Only
+ applicable on the prover side when the action is `request-accept`.
+ RequestPresentationInput:
+ required:
+ - connectionId
+ type: object
+ properties:
+ connectionId:
+ type: string
+ description: The unique identifier of an established connection between
+ the verifier and the prover.
+ format: uuid
+ example: bc528dc8-69f1-4c5a-a508-5f8019047900
+ options:
+ $ref: '#/components/schemas/Options'
+ proofs:
+ type: array
+ items:
+ $ref: '#/components/schemas/ProofRequestAux'
+ description: The type of proofs requested in the context of this proof presentation
+ request (e.g., VC schema, trusted issuers, etc.)
+ example: []
+ credentialFormat:
+ type: string
+ description: The credential format (default to 'JWT')
+ example: JWT
+ Service:
+ required:
+ - id
+ - type
+ - serviceEndpoint
+ type: object
+ properties:
+ id:
+ type: string
+ description: |-
+ The id of the service.
+ Requires a URI fragment when use in create / update DID.
+ Returns the full ID (with DID prefix) when resolving DID
+ example: service-1
+ type:
+ description: Service type. Can contain multiple possible values as described
+ in the [Create DID operation](https://github.com/input-output-hk/prism-did-method-spec/blob/main/w3c-spec/PRISM-method.md#create-did)
+ under the construction section.
+ example: Single(LinkedDomains)
+ oneOf:
+ - type: array
+ items:
+ type: string
+ - type: string
+ serviceEndpoint:
+ $ref: '#/components/schemas/Json'
+ description: A service expressed in the DID document. https://www.w3.org/TR/did-core/#services
+ Str:
+ required:
+ - value
+ type: object
+ properties:
+ value:
+ type: string
+ UpdateEntityNameRequest:
+ required:
+ - name
+ type: object
+ properties:
+ name:
+ type: string
+ description: New name of the entity
+ example: John Doe
+ minLength: 1
+ maxLength: 128
+ UpdateEntityWalletIdRequest:
+ required:
+ - walletId
+ type: object
+ properties:
+ walletId:
+ type: string
+ description: The walletId owned by the entity
+ format: uuid
+ example: 00000000-0000-0000-0000-000000000000
+ UpdateManagedDIDRequest:
+ type: object
+ properties:
+ actions:
+ type: array
+ items:
+ $ref: '#/components/schemas/UpdateManagedDIDRequestAction'
+ UpdateManagedDIDRequestAction:
+ required:
+ - actionType
+ type: object
+ properties:
+ actionType:
+ $ref: '#/components/schemas/ActionType'
+ addKey:
+ $ref: '#/components/schemas/ManagedDIDKeyTemplate'
+ removeKey:
+ $ref: '#/components/schemas/RemoveEntryById'
+ addService:
+ $ref: '#/components/schemas/Service'
+ removeService:
+ $ref: '#/components/schemas/RemoveEntryById'
+ updateService:
+ $ref: '#/components/schemas/UpdateManagedDIDServiceAction'
+ patchContext:
+ $ref: '#/components/schemas/PatchContextAction'
+ description: |-
+ A list of actions to perform on DID document.
+ The field `addKey`, `removeKey`, `addService`, `removeService`, `updateService`, `patchContext` must corresponds to
+ the `actionType` specified. For example, `addKey` must be present when `actionType` is `ADD_KEY`.
+ UpdateManagedDIDServiceAction:
+ required:
+ - id
+ type: object
+ properties:
+ id:
+ type: string
+ description: The id of the service to update
+ example: service-1
+ type:
+ description: The type of the service
+ example: LinkedDomains
+ oneOf:
+ - type: array
+ items:
+ type: string
+ - type: string
+ serviceEndpoint:
+ $ref: '#/components/schemas/Json'
+ description: A patch to existing Service. 'type' and 'serviceEndpoint' cannot
+ both be empty.
+ VerificationMethod:
+ required:
+ - id
+ - type
+ - controller
+ - publicKeyJwk
+ type: object
+ properties:
+ id:
+ type: string
+ description: The identifier for the verification method.
+ example: did:prism:4a5b5cf0a513e83b598bbea25cd6196746747f361a73ef77068268bc9bd732ff#key-1
+ type:
+ type: string
+ description: The type of the verification method.
+ example: JsonWebKey2020
+ controller:
+ type: string
+ description: The DID that controls the verification method.
+ example: did:prism:4a5b5cf0a513e83b598bbea25cd6196746747f361a73ef77068268bc9bd732ff
+ publicKeyJwk:
+ $ref: '#/components/schemas/PublicKeyJwk'
+ description: A cryptographic public key expressed in the DID document. https://www.w3.org/TR/did-core/#verification-methods
+ VerificationPolicy:
+ required:
+ - self
+ - kind
+ - id
+ - nonce
+ - name
+ - description
+ - createdAt
+ - updatedAt
+ type: object
+ properties:
+ self:
+ type: string
+ kind:
+ type: string
+ id:
+ type: string
+ format: uuid
+ nonce:
+ type: integer
+ format: int32
+ name:
+ type: string
+ description:
+ type: string
+ createdAt:
+ type: string
+ format: date-time
+ updatedAt:
+ type: string
+ format: date-time
+ constraints:
+ type: array
+ items:
+ $ref: '#/components/schemas/VerificationPolicyConstraint'
+ VerificationPolicyConstraint:
+ required:
+ - schemaId
+ type: object
+ properties:
+ schemaId:
+ type: string
+ trustedIssuers:
+ type: array
+ items:
+ type: string
+ VerificationPolicyInput:
+ required:
+ - name
+ - description
+ type: object
+ properties:
+ id:
+ type: string
+ format: uuid
+ name:
+ type: string
+ description:
+ type: string
+ constraints:
+ type: array
+ items:
+ $ref: '#/components/schemas/VerificationPolicyConstraint'
+ VerificationPolicyPage:
+ required:
+ - self
+ - kind
+ - pageOf
+ type: object
+ properties:
+ self:
+ type: string
+ kind:
+ type: string
+ pageOf:
+ type: string
+ next:
+ type: string
+ previous:
+ type: string
+ contents:
+ type: array
+ items:
+ $ref: '#/components/schemas/VerificationPolicy'
+ WalletDetail:
+ required:
+ - id
+ - name
+ - createdAt
+ - updatedAt
+ type: object
+ properties:
+ id:
+ type: string
+ description: A wallet ID
+ format: uuid
+ example: 00000000-0000-0000-0000-000000000000
+ name:
+ type: string
+ description: The name of the wallet
+ example: my-wallet-1
+ createdAt:
+ type: string
+ description: The `createdAt` timestamp of the wallet.
+ format: date-time
+ example: '2023-01-01T00:00:00Z'
+ updatedAt:
+ type: string
+ description: The `updateddAt` timestamp of the wallet.
+ format: date-time
+ example: '2023-01-01T00:00:00Z'
+ WalletDetailPage:
+ required:
+ - self
+ - kind
+ - pageOf
+ type: object
+ properties:
+ self:
+ type: string
+ kind:
+ type: string
+ pageOf:
+ type: string
+ next:
+ type: string
+ previous:
+ type: string
+ contents:
+ type: array
+ items:
+ $ref: '#/components/schemas/WalletDetail'
+ WebhookNotification:
+ required:
+ - id
+ - url
+ - customHeaders
+ - createdAt
+ type: object
+ properties:
+ id:
+ type: string
+ description: ID of webhook notification resource
+ format: uuid
+ example: 00000000-0000-0000-0000-000000000000
+ url:
+ type: string
+ description: A URL of webhook for event notification
+ example: http://example.com
+ customHeaders:
+ $ref: '#/components/schemas/Map_String'
+ createdAt:
+ type: string
+ description: A time which the webhook notification resource was created.
+ format: date-time
+ example: '1970-01-01T00:00:00Z'
+ WebhookNotificationPage:
+ required:
+ - self
+ - kind
+ - pageOf
+ type: object
+ properties:
+ self:
+ type: string
+ kind:
+ type: string
+ pageOf:
+ type: string
+ next:
+ type: string
+ previous:
+ type: string
+ contents:
+ type: array
+ items:
+ $ref: '#/components/schemas/WebhookNotification'
+ securitySchemes:
+ adminApiKeyAuth:
+ type: apiKey
+ name: x-admin-api-key
+ in: header
+ apiKeyAuth:
+ type: apiKey
+ name: apikey
+ in: header
+ jwtAuth:
+ type: http
+ scheme: bearer