> For the complete documentation index, see [llms.txt](https://docs.indicio.tech/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.indicio.tech/developer/indicio-proven-r/how-to-guides/proven-mobile-sdk.md).

# Proven Mobile SDK

## Proven Mobile SDK Documentation

The Indicio Holdr SDK (Software Development Kit) supports Android and iOS platforms and provides holder capabilities that are compatible with many Aries protocols. Consumption of the Holdr SDK will allow an application to have its own Aries Askar wallet for holding digital credentials that conform to the Anoncreds specification, communicate with ledgers through IndyVDR, and generate zero trust proofs for information verification through Anoncreds-RS.

### Supported Aries protocols:

* Did Exchange 1.0
* Out Of Band 1.1
* Coordinate Mediation 1.0
* Pickup 2.0
* Issue Credential 2.0
* Present Proof 2.0

### Supported DID methods:

* Did:Peer:1
* Did:Peer:2
* Did:Key

### Supported credential formats:

* Anoncreds

## API Overview

Sudo Typescript syntax is used to express the API. Any parameter that could be undefined is optional in Kotlin and React Native. Due to limitations with Swift code generation, not all Swift functions have default parameters when a value is optional and will need to have nil provided explicitly. A function using the await keyword is async in React Native and Swift and suspended in Kotlin.

[Agent API](#agent)

[DidExchange API](#didexchange)

[OutOfBand API](#out-of-band)

[Credentials API](#credentials)

[Proofs API](#proofs)

[Routing API](#routing)

[Events API](#events)

## Agent

### async agent.start(): void

Starts the agent and connects to the default mediator if a mediation configuration is provided.

```
await agent.start(
    timeout: 10_000 // Optional -- time limit in MS to connect to mediator
)
```

### async agent.stop(): void

Stops all even listeners and websockets and properly closes the wallet’s database files, so the agent can be used later.

```
await agent.stop()
```

### async agent.delete(): void

Deletes the agent and all data associated with it, essentially resetting the wallet.

```
await agent.delete()
```

## DidExchange

### async didExchange.acceptOutOfBandInvitation(): DidExchangeRecord

Sends a `didExchange` request to the agent associated with the provided out-of-band record.

```
const didExchangeRecord = await agent.didExchange.acceptOutOfBandInvitation(
    outOfBandRecord: OutOfBandRecord, // Record id (String) in React Native
    autoAcceptConnection: Boolean | undefined,
    label: String | undefined,
    alias: String | undefined,
    routingParam: Routing | undefined // Not available in React Native
)
```

### async didExchange.acceptResponse(): DidExchangeRecord

Completes the `didExchange` handshake by sending a complete message to the agent associated with the provided `didExchangeId`.

```
const didExchangeRecord = await agent.didExchange.acceptResponse(
    didExchangeId: String
)
```

### async didExchange.requestConnection(): DidExchangeRecord

Used when the auto-accept connection is disabled on the agent. This function is used to complete the started `didExchange` process once an out-of-band invitation has been processed, and a `didExchange` record is created but not auto-accepted.

```
const didExchangeRecord = await agent.didExchange(
    didExchangeId: String,
    outOfBandId: String,
    routingParam: Routing | undefined // Not available in React Native
)
```

### async didExchange.sendPing(): TrustPingMessage

Used to send a trust ping to another agent to ensure we can reach the agent.

```
const trustPingMessage = await agent.didExchange.sendPing(
    exchangeId: String,
    responseRequested: Boolean,
    returnRouting: Boolean
)
```

### async didExchange.returnWhenIsConnected(): DidExchangeStateChangedEvent?

Waits until the provided `didExchangeId` reaches a state of `Done` or until the provided timeout is reached.

```
const didExchangeStateChangedEvent: DidExchangeStateChangedEvent? = await agent.didExchange.returnWhenIsConnected(
    didExchangeId: String,
    timeOutMs: Number | Long
)
```

### async didExchange.getAll(): Array\[DidExchangeRecord]

Retrieves all `didExchange` records.

```
const records: Array<DidExchangeRecord> = await agent.didExchange.getAll()
```

### async didExchange.findAllByQuery(): Array\[DidExchangeRecord]

Finds all records that have tags matching the given query.

```
const records: Array<DidExchangeRecord> = await agent.didExchange.findAllByQuery(
    query: Query // Record<String, String> in React Native. Malformed Query will throw
)
```

### async didExchange.getById(): DidExchangeRecord

Retrieves the record with the provided ID or throws a `RecordNotFoundError`.

```
const record = await agent.didExchange.getById(
    didExchangeId: String
)
```

### async didExchange.findById(): DidExchangeRecord?

Finds the record with the given ID or returns `null` if not found.

```
const record: DidExchangeRecord? = await agent.didExchange.findById(
    didExchangeId: String
)
```

### async didExchange.deleteById(): void

Deletes the record with the given ID or throws `RecordNotFoundError` if it does not exist.

```
await agent.didExchange.deleteById(
    didExchangeId: String
)
```

### async didExchange.findAllByOutOfBandId(): Array\[DidExchangeRecord]

Finds all records associated with the given out-of-band ID.

```
const records: Array<DidExchangeRecord> = await agent.didExchange.getAllByOutOfBandId(
  outOfBandId: String
)
```

### async didExchange.findByDid(): DidExchangeRecord?

Finds the record associated with the provided Did.

```
const record: DidExchangeRecord? = await agent.didExchange.findByDid(
    did: String
)
```

### async didExchange.findByInvitationDid(): DidExchangeRecord?

Finds the record whose invitation contained the provided Did.

```
const record: DidExchangeRecord? = await agent.didExchange.findByInvitationDid(
    did: String
)
```

## Out Of Band

### async outOfBand.createInvitation(): OutOfBandRecord

Creates an out-of-band invitation and corresponding out-of-band record that is returned.

```
const record = await agent.outOfBand.createInvitation(
    label: String | undefined,
    alias: String | undefined,
    goalCode: String | undefined,
    goal: String | undefined,
    handShake: Boolean | undefined,
    messages: Array<BaseMessage> | undefined,
    multiUseInvitation: Boolean | undefined,
    autoAcceptConnection: Boolean | undefined,
    routingParam: Routing | undefined, // Not available in React Native
    appendedAttachment: Array<Attachment> | undefined
)
```

### outOfBand.parseInvitation(): OutOfBandInvitationMessage

Parses a URL encoded invitation into an `OutOfBandInvitationMessage`.

```
const message = agent.outOfBand.parseInvitation(
    invitationUrl: String
)
```

### async outOfBand.receiveInvitation(): AcceptInvitationResponse

Processes the provided invitation and potentially starts or completes `didExchange` protocol.

```
const invitationResponse = await agent.outOfBand.receiveInvitation(
    invitation: OutOfBandInvitationMessage,
    label: String | undefined,
    alias: String | undefined,
    autoAcceptConnection: Boolean | undefined,
    reuseConnection: Boolean | undefined,
    routingParam: Routing | undefined, // Not available in React Native
    acceptInvitationTimeOutMs = Number | Long | undefined
)
```

### async outOfBand.receiveImplicitInvitation(): AcceptInvitationResponse

Processes an invitation where the invitation message is not present and the agent is implicitly invited.

```
const invitationResponse = await agent.outOfBand.receiveImplicitInvitation(
    label: String | undefined,
    alias: String | undefined,
    autoAcceptConnection: Boolean | undefined,
    reuseConnection: Boolean | undefined,
    routingParam: Routing | undefined, // Not available in React Native
    acceptInvitationTimeOutMs: Number | Long | null,
    did: String,
    handShakeProtocol: Array<String> | null
)
```

### async outOfBand.acceptInvitation(): AcceptInvitationResponse

Accepts the invitation of an existing out-of-band record. It is not commonly used.

```
const invitationResponse = await agent.outOfBand.acceptInvitation(
    outOfBand: String,
    autoAcceptConnection: Boolean,
    reuseConnection: Boolean,
    label: String,
    alias: String | null,
    routingParam: Routing | null,
    timeOutMs: Number | undefined
)
```

### async outOfBand.findByInvitationId(): OutOfBandRecord?

Finds the out-of-band record with the corresponding invitation ID, or returns `null`.

```
const record: OutOfBandRecord? = await agent.outOfBand.findByReceivedInvitationId(
    receivedInvitationId: String
)
```

### async outOfBand.findByCreatedInvitationId(): OutOfBandRecord?

Finds the out-of-band record that corresponds to the invitation with the given ID that we have created, or returns `null`.

```
const record: OutOfBandRecord? = await agent.outOfBand.findByCreatedInvitationId(
    createdInvitationId: String
)
```

### async outOfBand.getAll(): Array\[OutOfBandRecord]

Retrieves all of the out-of-band records held by the agent.

```
const records: Array<OutOfBandRecord> = await agent.outOfBand.getAll()
```

### async outOfBand.getAllByQuery(): Array\[OutOfBandRecord]

Retrieves all out-of-band records that match the provided query.

```
const records: Array<OutOfBandRecord> = await agent.outOfBand.getAllByQuery(
    query: Query // Record<String, String> in React Native. Malformed Query will throw
)
```

### async outOfBand.getById(): OutOfBandRecord

Retrieves the record with the provided ID or throws `RecordNotFoundError`.

```
const record = await agent.outOfBand.getById(
    outOfBandId: String
)
```

### async outOfBand.findById(): OutOfBandRecord?

Finds the record with the given ID or returns `null`.

```
const record: OutOfBandRecord? = await agent.outOfBand.findById(
    outOfBandId: String
)
```

### async outOfBand.deleteById(): void

Deletes the record with the given ID or throws `RecordNotFoundError` if no such record exists.

```
await agent.outOfBand.deleteById(
    outOfBandId: String
)
```

## Credentials

### async credentials.findAllCredentialsBySchemaId(): Array\[CredentialRecord]

Finds all credentials whose schema ID matches the provided schema ID.

```
const records: Array<CredentialRecord> = await agent.credentials.findAllCredentialsBySchemaId(
    schemaId: String
)
```

### async credentials.proposeCredential(): CredentialExchangeRecord

Sends a proposal to the connection with the associated `didExchangeId` that we want the specified credential from.

```
const records: Array<CredentialRecord> = await agent.credentials.findAllCredentialsBySchemaId(
    schemaId: String
)
```

### async credentials.acceptOffer(): CredentialExchangeRecord

Accepts the offer associated with the provided credential exchange record.

```
const record = await agent.credentials.acceptOffer(
    credentialExchangeId: String,
    autoAcceptCredential: Boolean | undefined,
    comment: String | null | undefined
)
```

### async credentials.acceptCredential(): CredentialExchangeRecord

Accepts the issue credential and saves it to the agent's wallet.

```
const record = agent.credentials.acceptCredential(
    credentialExchangeId: String
)
```

### async credentials.findByRecordId(): CredentialExchangeRecord?

Finds the record with the given ID or returns `null`.

```
const record: CredentialExchangeRecord? = await agent.credentials.findByRecordId(
    credentialExchangeId: String
)
```

### async credentials.findAllByState(): Array\[CredentialExchangeRecord]

Finds all credentials whose exchange state matches the provided state.

```
const records: Array<CredentialExchangeRecord> = await agent.credentials.findAllByState(
    state: CredentialState
)
```

### async credentials.findAllByStateAndDidExchangeId(): Array\[CredentialExchangeRecord]

Finds all records whose state matches the given state and came from the connection associated with the given `didExchangeId`.

```
const records: Array<CredentialExchangeRecord> = await agent.credentials.findAllByStateAndDidExchangeId(
    state: CredentialState,
    didExchangeId: String
)
```

### async credentials.getAll(): Array\[CredentialExchangeRecord]

Retrieves all of the `credentialExchangeRecords`.

```
const records: Array<CredentialExchangeRecord> = await agent.credentials.getAll()
```

### async credentials.findByThreadIdAndDidExchangeId(): CredentialExchangeRecord?

Finds the credential exchange record that has matching `threadId` and `didExchangeId` (optional) or returns `null`.

```
const record = await agent.credentials.findByThreadIdAndDidExchangeId(
    threadId: String,
    didExchangeId: String | null
)
```

### async credentials.getByThreadIdAndDidExchangeId(): CredentialExchangeRecord

Retrieves the credential exchange record that has matching `threadId` and `didExchangeId` (optional): otherwise it throws `RecordNotFoundError`.

## Proofs

### async proofs.autoAcceptProof(): ProofRecord

Attempts to auto-accept the proof with the provided ID from the provided `didExchange` connection, it will throw `ProvenError` if the proof cannot be satisfied.

```
const record = await agent.proofs.autoAcceptProof(
    proofId: String,
    exchangeId: String
)
```

### async proofs.acceptProof(): ProofRecord

Accepts the given proof using the provided credential selections, it will throw `ProvenError` if the credential selection is invalid or insufficient.

```
const record = await agent.proofs.acceptProof(
    proofData: PresentationData
)
```

### async proofs.getCredentialsForProofRequest(): PresentationData

Retrieves a mapping of proof requests to valid credentials for the request that require further selection. Throws `RecordNotFoundError` if the proof cannot be satisfied with the agent's current credentials.

```
const creds = await agent.proofs.getCredentialsForProofRequest(
    proofId: String,
    exchangeId: String,
    nonRevoked: Boolean | undefined
)
```

### async proofs.autoSelectCredentialsForProofRequest(): PresentationData

Finds credentials that satisfy the proof request and automatically selects valid credentials if there are multiple options. Throws `RecordNotFoundError` if the proof cannot be satisfied with the agent's current credentials.

```
const creds = await agent.proofs.autoSelectCredentialsForProofRequest(
    proofId: String,
    exchangeId: String,
    nonRevoked: Boolean | undefined
)
```

### async proofs.getProofRequestsForConnection(): Array\[ProofRecord]

Retrieves the proof records for a given connection from the `didExchange ID`.

```
const records: Array<ProofRecord> = await agent.proofs.getProofRequestsForConnection(
    didExchangeId: String
)
```

## Routing

### async routing.initialize(): void

Starts or resumes the mediation to the default `mediator`. Called in `agent.start` by default.

```
await agent.routing.initialize()
```

### async routing.initiateMessagePickup(): void

Instructs the agent to attempt to pick up messages from the provided `mediator` record or the default mediator if not provided.

```
await agent.routing.initiateMessagePickup(
    mediator: MediationRecord | null | undefined // Record id is used in React Native
)
```

### async routing.findDefaultMediator(): MediationRecord?

Finds the default mediator if one is set, otherwise returns `null`.

```
const record: MediationRecord? = await agent.routing.findDefaultMediator()
```

### async routing.discoverMediation(): MediationRecord?

Finds the default mediator’s record. If the default mediator is found but not granted, this will throw `ProvenError`.

```
const record: MediationRecord? = await agent.routing.discoverMediation()
```

### async routing.setDefaultMediator(): MediationRecord

Sets the default mediator.

```
const record = await agent.routing.setDefaultMediator(
    mediation: MediationRecord | String // Provide the record or the record id. React native only uses Id
)
```

### async routing.requestMediation(): MediationRecord

Requests mediation from the given `didExchange` connection.

```
const record = await agent.routing.requestMediation(
    didExchange: DidExchangeRecord | String // Provide the record or the record id. React native only uses Id
)
```

### async routing.getByExchangeId(): MediationRecord

Retrieves the mediation record with the provided `didExchange` ID or throws `RecordNotFoundError`.

```
const record = await agent.routing.getByExchangeId(
    exchangeId: String
)
```

### async routing.findByExchangeId(): MediationRecord

Finds the mediation record with the given `didExchange` ID or returns `null` if not found.

```
const record: MediationRecord? = await agent.routing.findByExchangeId(
    exchangeId: String
)
```

### async routing.getMediators(): Array\[MediationRecord]

Retrieves all of the meditation records.

```
const records: Array<MediationRecord> = await agent.routing.getMediators()
```

### async routing.findDefaultMediatorExchange(): DidExchangeRecord?

Finds the `didExchange` record for the default mediator or returns `null` if not found

```
const record: DidExchangeRecord? = await agent.routing.findDefaultMediatorExchange()
```

### async routing.provision(): MediationRecord?

Attempts to complete the mediation request from the provided `didExchange` record in the given time. If it doesn’t complete, it will throw `CancellatinException`.

```
const record: MediationRecord? = await agent.routing.provision(
    didExchangeRecord: DidExchangeRecord,
    timeOutMs: Number | Long | undefined
)
```

### async routing.getRouting(): Routing

Retrieves the routing for this mediator. This is not available in React Native.

```
const routing = await agent.routing.getRouting(
    mediatorId: String,
    useDefaultMediator: Boolean | undefined
)
```

## Basic Messaging

### async basicMessages.send(): BasicMessageRecord

Sends a basic message to another connection.

```
const sentMessageRecord = await agent.basicMessages.send(
    didExchangeId: String, // ID of target
    content: String, // Message content to be sent
    locale: String = "en", // L10nDecorator version (defaults to "en")
    comment: String? // Comment on message
)
```

### async basicMessages.findById(): BasicMessageRecord

Finds a basic message record by ID.

```
const basicMessage = await agent.basicMessages.findById(
    basicMessageRecordId: String // Record ID to be retrieved
)
```

### async basicMessages.getAll(): Array

Retrieves all basic messages.

```
const basicMessages = await agent.basicMessages.getAll()
```

### async basicMessages.findByComment(): Array

Finds all basic messages with matching comments.

```
const basicMessages = await agent.basicMessages.findByComment(
    comment: String // Comment to search for
)
```

### async basicMessages.findByDidExchangeId(): Array

Finds all basic messages from the recipient.

```
const basicMessages = await agent.basicMessages.findByDidExchangeId(
    didExchangeId: String // Exchange ID to look for
)
```

### async basicMessages.findByRole(): Array

Finds all basic messages that match the role.

```
const basicMessages = await agent.basicMessages.findByRole(
    role: BasicMessageRole // Role to look for
)
```

## Events

#### React Native

React Native events take a callback function and return a function to remove the callback.

```
const remove = agent.events.registerDidExchangeHandler((event) => {
    console.log("Got a didExchange event")
})

remove() // cancels the event callback
```

The events that can have a handler registered are:&#x20;

* `registerDidExchangeHandler`
* `registerProofsHandler`
* `registerCredentialsHandler`
* `registerAgentHandler`
* `registerBasicMessageHandler`
* `registerRecordHandler`
* `registerWebSocketHandler`

#### Kotlin

Directly retrieve the event flow and use Kotlin's flow API using the events API. There is also a provided co-routine context on the events object.

```
/ May not be defined if there were issues with agent initialization
val didExchange: DidExchangeEvents? = agent.events.getDidExchangeEvents()

agent.events.scope.launch {
    didExchange.events.onEach{
        println("Got a didExchange event")
    }.collect() // Make sure to call collect or events will not be processed
}

```

The events that can be retrieved in Kotlin are the following:&#x20;

* `getDidExchangeEvents`
* `getAgentEvents`
* `getCredentialEvents`
* `getEventBusEvents` (Record update events)
* `getMessageEvents` (Events for all messages)
* `getProofEvents`
* `getBasicMessageEvents`
* `getTrustPingEvents`
* `getWebSocketEvents`

#### Swift

The following methods wrap events so you can easily listen to them without a third-party library or if you are using Objective-C:

* `onDidExchangeStateChanged`
* `onCredentialStateChanged`
* `onTrustPingEvent`
* `onAgentEvent`&#x20;
* `onRecordEvent`
* `onProofEvent`
* `onWebsocketEvent`
* `onBasicMessageEvent`

**Swift**

```
let removeListener = agent.events.onDidExchangeStateChanged { event in
  // Handle DidExchangeStateChangedEvent here
}
// Remove listener when no longer needed
removeListener(nil)
```

<figure><img src="/files/EEQp0oJJojvK2fP96rHq" alt=""><figcaption></figcaption></figure>


---

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

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

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

```
GET https://docs.indicio.tech/developer/indicio-proven-r/how-to-guides/proven-mobile-sdk.md?ask=<question>&goal=<endgoal>
```

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

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

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