Wallet API¶
The Wallet API is the main interface for interacting with a cloud wallet. It is primarly used when you're providing custom wallet experience and building your own digital wallet integration. If you'd like to use Trinsic's integrated cloud wallet app, you likely won't need to use this API.
Migrating from Account API?
Check out our migration guide on how to migrate your code that uses the deprecated Account API.
Create Wallet¶
Create a new wallet and return the authentication token and wallet information about the newly created wallet.
var createWalletRequest = new CreateWalletRequest {
EcosystemId = "test-ecosystem",
Description = "user123",
Identity = new CreateWalletRequest.Types.ExternalIdentity {
Identity = "test@trinsic.id",
Provider = IdentityProvider.Email
}
};
var createWalletResponse = await trinsic.Wallet.CreateWalletAsync(createWalletRequest);
// Response:
// "authToken": "dGhpcyBpcyBhbiBleGFtcGxlIGF1dGhlbmNpdGlvbiB0b2tlbgo=",
// "tokenId": "0b4f42cb-4d44-4629-89dd-47b814229ffe",
// "wallet":
// "walletId": "urn:trinsic:wallets:z7438uW5X4gZ1rZsiZaBdxX",
// "publicDid": "did:key:123456"
Authenticate¶
Authenticate and return an auth token for an existing wallet using one of the associated external identities. This endpoint requires that the wallet user has previously added at least one external identity using the above endpoints.
Once a token is obtained, it can be reused for future sessions -- users don't need to authenticate if they already have a valid token. You can store the auth token in secure enclaves on the users device, browser, etc.
When should users authenticate?
- If your integration solution doesn't manage the wallet tokens, users may need to re-authenticate on their device to get a new auth token
- Users want to log in to a different device using their email or phone number
- Returning users that have lost their previous session and require new auth token
AuthenticateInit¶
// Step 1 - initiate authentication challenge
var authenticateInitRequest = new AuthenticateInitRequest {
Identity = "test@trinsic.id",
Provider = IdentityProvider.Email,
EcosystemId = "test-ecosystem" // short name or full ecosystem ID
};
var authenticateInitResponse = await trinsic.Wallet.AuthenticateInitAsync(authenticateInitRequest);
AcquireAuthTokenInit
endpoint Pass this challenge back to the AcquireAuthTokenConfirm
endpointAuthenticateConfirm¶
// Step 2 - confirm authentication response
var authenticateConfirmRequest = new AuthenticateConfirmRequest {
Challenge = authenticateInitResponse.Challenge,
Response = "123456" // OTP code
};
var authenticateConfirmResponse = await trinsic.Wallet.AuthenticateConfirmAsync(authenticateConfirmRequest);
// Response:
// "authToken": "dGhpcyBpcyBhbiBleGFtcGxlIGF1dGhlbmNpdGlvbiB0b2tlbgo="
// use the new token to make authenticated calls
// var options = new TrinsicOptions { AuthToken = AuthenticateConfirmResponse.AuthToken };
// trinsic = new TrinsicService(options);
AcquireAuthTokenInit
endpointAdd External Identity¶
This service is used to attach external identity, such as email or phone number, to a wallet. The purpose of this process is to allow
the user to authenticate to their existing wallet (using the Authenticate
endpoint) to get an auth token.
This may be needed if the user is logging in on a different device, have lost access to the initial auth token, etc.
The process for adding external identity is based on confirming an OTP code that will be sent to the user's email address or phone number. To do this, you should call the
services AddExternalIdentityInit
and AddExternalIdentityConfirm
.
AddExternalIdentityInit¶
// the two endpoints below require authenticated user context
// var options = new TrinsicOptions { AuthToken = "<auth token>" };
// var trinsic = new TrinsicService(options);
// Step 1 - initiate identity challenge
var addExternalIdentityInitRequest = new AddExternalIdentityInitRequest {
Identity = "test@trinsic.id",
Provider = IdentityProvider.Email
};
var addExternalIdentityInitResponse = await trinsic.Wallet.AddExternalIdentityInitAsync(addExternalIdentityInitRequest);
AddExternalIdentityConfirm
endpointAddExternalIdentityConfirm¶
// Step 2 - confirm challenge response
var addExternalIdentityConfirmRequest = new AddExternalIdentityConfirmRequest {
Challenge = addExternalIdentityInitResponse.Challenge,
Response = "123456" // OTP code
};
var addExternalIdentityConfirmResponse = await trinsic.Wallet.AddExternalIdentityConfirmAsync(addExternalIdentityConfirmRequest);
AddExternalIdentityInit
endpointRemove External Identity¶
Removes an external identity from the associated identities of the authenticated wallet.
// this endpoint require authenticated user context
// var options = new TrinsicOptions { AuthToken = "<auth token>" };
// var trinsic = new TrinsicService(options);
var removeExternalIdentityRequest = new RemoveExternalIdentityRequest {
Identity = "test@trinsic.id",
};
var removeExternalIdentityResponse = await trinsic.Wallet.RemoveExternalIdentityAsync(removeExternalIdentityRequest);
Insert Item¶
Stores a credential (or any other JSON object) in a wallet.
let insertItemResponse = await trinsic.wallet().insertItem(
InsertItemRequest.fromPartial({
itemJson: issueResponse.documentJson,
}),
);
var insertItemResponse =
await trinsic.Wallet.InsertItemAsync(new() { ItemJson = credentialJson.DocumentJson });
insert_response = await trinsic.wallet.insert_item(
request=InsertItemRequest(
item_json=credential, item_type="VerifiableCredential"
)
)
insertResponse, err := trinsic.Wallet().InsertItem(context.Background(), &wallet.InsertItemRequest{
ItemJson: credentialJson,
ItemType: "VerifiableCredential",
})
var insertResponse =
trinsic
.wallet()
.insertItem(
InsertItemRequest.newBuilder()
.setItemJson(credentialJson)
.setItemType("VerifiableCredential")
.build())
.get();
What can be stored in a wallet?
Wallets are mainly intended to hold Verifiable Credentials, but can technically store any JSON blob.
If you store a Verifiable Credential in a Wallet, ensure that its item_type
is VerifiableCredential
.
Otherwise, ensure its item_type
is not VerifiableCredential
.
Get Item¶
Retrieves an item of the wallet by its ID.
let getItemResponse = await trinsic.wallet().getItem({
itemId: itemId,
});
var getItemResponse = await trinsic.Wallet.GetItemAsync(new GetItemRequest {
ItemId = itemId
});
item = await trinsic.wallet.get_item(request=GetItemRequest(item_id))
getResponse, err := trinsic.Wallet().GetItem(context.Background(), &wallet.GetItemRequest{
ItemId: itemId,
})
var getResponse =
trinsic.wallet().getItem(GetItemRequest.newBuilder().setItemId(itemId).build()).get();
GetItemRequest
Get Wallet¶
Retrieves information about wallets in the ecosystem. These endpoints can only be called by a Provider, so make sure you authenticate as it before calling them.
GetWalletInfo¶
Retrieves information about a wallet by its ID.
//trinsic.options.authToken = trinsic.provider().options.authToken;
let getWalletInfoResponse = await trinsic.wallet().getWalletInfo(
GetWalletInfoRequest.fromPartial({
walletId: createWalletResponse.wallet?.walletId,
}),
);
var getWalletInfoResponse = await trinsic.Wallet.GetWalletInfoAsync(
new GetWalletInfoRequest {
WalletId = createWalletResponse.Wallet.WalletId
}
);
trinsic.set_auth_token(trinsic.provider.options.auth_token)
get_wallet_info_response = await trinsic.wallet.get_wallet_info(
request=GetWalletInfoRequest(
wallet_id=create_wallet_response.wallet.wallet_id
)
)
package services
import (
"context"
"encoding/json"
"github.com/trinsic-id/sdk/go/proto/services/universalwallet/v1/wallet"
"testing"
"github.com/stretchr/testify/assert"
)
func TestWalletService(t *testing.T) {
assert2 := assert.New(t)
trinsic, ecosystem, err := CreateTestTrinsicWithNewEcosystem()
assert2.Nil(err)
// Create a new account in the ecosystem
createResponse, err := trinsic.Wallet().CreateWallet(context.Background(), &wallet.CreateWalletRequest{
EcosystemId: ecosystem.Id,
Description: nil,
})
assert2.Nil(err)
walletId := createResponse.Wallet.WalletId
valuesBytes, _ := json.Marshal(struct{ name string }{name: "A Realperson"})
credentialJson := string(valuesBytes)
// insertItemWallet() {
insertResponse, err := trinsic.Wallet().InsertItem(context.Background(), &wallet.InsertItemRequest{
ItemJson: credentialJson,
ItemType: "VerifiableCredential",
})
// }
assert2.NotNil(insertResponse)
assert2.Nil(err)
itemId := insertResponse.ItemId
// getItem() {
getResponse, err := trinsic.Wallet().GetItem(context.Background(), &wallet.GetItemRequest{
ItemId: itemId,
})
//}
assert2.Nil(err)
assert2.NotNil(getResponse)
// deleteItem() {
deleteResponse, err := trinsic.Wallet().DeleteItem(context.Background(),
&wallet.DeleteItemRequest{
ItemId: itemId,
})
//}
assert2.Nil(err)
assert2.NotNil(deleteResponse)
// searchWalletBasic() {
searchResponse, err := trinsic.Wallet().SearchWallet(context.Background(), &wallet.SearchRequest{})
// }
assert2.NotNil(searchResponse)
assert2.Nil(err)
// deleteWallet() {
deleteWalletResponse, err := trinsic.Wallet().DeleteWallet(context.Background(),
&wallet.DeleteWalletRequest{
Account: &wallet.DeleteWalletRequest_WalletId{
WalletId: walletId,
},
})
//}
assert2.Nil(err)
assert2.NotNil(deleteWalletResponse)
}
package trinsic;
import java.io.IOException;
import java.util.concurrent.ExecutionException;
import org.junit.jupiter.api.Assertions;
import trinsic.services.TrinsicService;
import trinsic.services.provider.v1.CreateEcosystemRequest;
import trinsic.services.universalwallet.v1.*;
public class WalletsDemo {
public static void main(String[] args)
throws IOException, ExecutionException, InterruptedException {
run();
}
public static void run() throws IOException, ExecutionException, InterruptedException {
// Create ecosystem
var trinsic = new TrinsicService(TrinsicUtilities.getTrinsicTrinsicOptions());
var ecosystemResponse =
trinsic.provider().createEcosystem(CreateEcosystemRequest.getDefaultInstance()).get();
var ecosystemId = ecosystemResponse.getEcosystem().getId();
var account =
trinsic
.wallet()
.createWallet(CreateWalletRequest.newBuilder().setEcosystemId(ecosystemId).build())
.get();
trinsic.setAuthToken(account.getAuthToken());
var walletId = account.getWallet().getWalletId();
var credentialJson =
"{\"foo\":\"bar\"}"; // Doesn't need to actually be a credential for this test
// insertItemWallet() {
var insertResponse =
trinsic
.wallet()
.insertItem(
InsertItemRequest.newBuilder()
.setItemJson(credentialJson)
.setItemType("VerifiableCredential")
.build())
.get();
// }
var itemId = insertResponse.getItemId();
// getItem() {
var getResponse =
trinsic.wallet().getItem(GetItemRequest.newBuilder().setItemId(itemId).build()).get();
// }
// Abuse scope to allow redeclaration of walletItems for docs injection niceness
{
// searchWalletBasic() {
var walletItems = trinsic.wallet().searchWallet().get();
// }
Assertions.assertEquals(1, walletItems.getItemsCount());
}
// Delete item in-between searches
// deleteItem() {
trinsic.wallet().deleteItem(DeleteItemRequest.newBuilder().setItemId(itemId).build()).get();
// }
{
// searchWalletSQL() {
var walletItems =
trinsic
.wallet()
.search(
SearchRequest.newBuilder()
.setQuery(
"SELECT c.id, c.type, c.data FROM c WHERE c.type ="
+ " 'VerifiableCredential'")
.build())
.get();
// }
Assertions.assertNotNull(walletItems);
Assertions.assertEquals(0, walletItems.getItemsCount());
}
// deleteWallet() {
trinsic
.wallet()
.deleteWallet(DeleteWalletRequest.newBuilder().setWalletId(walletId).build())
.get();
// }
System.out.println("Wallets demo successful");
trinsic.shutdown();
}
}
GetWalletFromExternalIdentity¶
Retrieves information about a wallet by its External Identity (email or phone number).
//trinsic.options.authToken = trinsic.provider().options.authToken;
let getWalletFromExternalIdentityResponse = await trinsic.wallet().getWalletFromExternalIdentity(
GetWalletFromExternalIdentityRequest.fromPartial({
identity: {
id: "test@trinsic.id",
provider: 1,
}
}),
);
var getWalletFromExternalIdentityRequest = new GetWalletFromExternalIdentityRequest {
Identity = new WalletExternalIdentity() {
Id = "test@trinsic.id",
Provider = IdentityProvider.Email
}
};
var getWalletFromExternalIdentityResponse = await trinsic.Wallet.GetWalletFromExternalIdentityAsync(getWalletFromExternalIdentityRequest);
trinsic.set_auth_token(trinsic.provider.options.auth_token)
get_wallet_from_external_identity_response = await trinsic.wallet.get_wallet_from_external_identity(
request=GetWalletFromExternalIdentityRequest(
identity={
"id": "test@trinsic.id",
"provider": 1
}
)
)
package services
import (
"context"
"encoding/json"
"github.com/trinsic-id/sdk/go/proto/services/universalwallet/v1/wallet"
"testing"
"github.com/stretchr/testify/assert"
)
func TestWalletService(t *testing.T) {
assert2 := assert.New(t)
trinsic, ecosystem, err := CreateTestTrinsicWithNewEcosystem()
assert2.Nil(err)
// Create a new account in the ecosystem
createResponse, err := trinsic.Wallet().CreateWallet(context.Background(), &wallet.CreateWalletRequest{
EcosystemId: ecosystem.Id,
Description: nil,
})
assert2.Nil(err)
walletId := createResponse.Wallet.WalletId
valuesBytes, _ := json.Marshal(struct{ name string }{name: "A Realperson"})
credentialJson := string(valuesBytes)
// insertItemWallet() {
insertResponse, err := trinsic.Wallet().InsertItem(context.Background(), &wallet.InsertItemRequest{
ItemJson: credentialJson,
ItemType: "VerifiableCredential",
})
// }
assert2.NotNil(insertResponse)
assert2.Nil(err)
itemId := insertResponse.ItemId
// getItem() {
getResponse, err := trinsic.Wallet().GetItem(context.Background(), &wallet.GetItemRequest{
ItemId: itemId,
})
//}
assert2.Nil(err)
assert2.NotNil(getResponse)
// deleteItem() {
deleteResponse, err := trinsic.Wallet().DeleteItem(context.Background(),
&wallet.DeleteItemRequest{
ItemId: itemId,
})
//}
assert2.Nil(err)
assert2.NotNil(deleteResponse)
// searchWalletBasic() {
searchResponse, err := trinsic.Wallet().SearchWallet(context.Background(), &wallet.SearchRequest{})
// }
assert2.NotNil(searchResponse)
assert2.Nil(err)
// deleteWallet() {
deleteWalletResponse, err := trinsic.Wallet().DeleteWallet(context.Background(),
&wallet.DeleteWalletRequest{
Account: &wallet.DeleteWalletRequest_WalletId{
WalletId: walletId,
},
})
//}
assert2.Nil(err)
assert2.NotNil(deleteWalletResponse)
}
package trinsic;
import java.io.IOException;
import java.util.concurrent.ExecutionException;
import org.junit.jupiter.api.Assertions;
import trinsic.services.TrinsicService;
import trinsic.services.provider.v1.CreateEcosystemRequest;
import trinsic.services.universalwallet.v1.*;
public class WalletsDemo {
public static void main(String[] args)
throws IOException, ExecutionException, InterruptedException {
run();
}
public static void run() throws IOException, ExecutionException, InterruptedException {
// Create ecosystem
var trinsic = new TrinsicService(TrinsicUtilities.getTrinsicTrinsicOptions());
var ecosystemResponse =
trinsic.provider().createEcosystem(CreateEcosystemRequest.getDefaultInstance()).get();
var ecosystemId = ecosystemResponse.getEcosystem().getId();
var account =
trinsic
.wallet()
.createWallet(CreateWalletRequest.newBuilder().setEcosystemId(ecosystemId).build())
.get();
trinsic.setAuthToken(account.getAuthToken());
var walletId = account.getWallet().getWalletId();
var credentialJson =
"{\"foo\":\"bar\"}"; // Doesn't need to actually be a credential for this test
// insertItemWallet() {
var insertResponse =
trinsic
.wallet()
.insertItem(
InsertItemRequest.newBuilder()
.setItemJson(credentialJson)
.setItemType("VerifiableCredential")
.build())
.get();
// }
var itemId = insertResponse.getItemId();
// getItem() {
var getResponse =
trinsic.wallet().getItem(GetItemRequest.newBuilder().setItemId(itemId).build()).get();
// }
// Abuse scope to allow redeclaration of walletItems for docs injection niceness
{
// searchWalletBasic() {
var walletItems = trinsic.wallet().searchWallet().get();
// }
Assertions.assertEquals(1, walletItems.getItemsCount());
}
// Delete item in-between searches
// deleteItem() {
trinsic.wallet().deleteItem(DeleteItemRequest.newBuilder().setItemId(itemId).build()).get();
// }
{
// searchWalletSQL() {
var walletItems =
trinsic
.wallet()
.search(
SearchRequest.newBuilder()
.setQuery(
"SELECT c.id, c.type, c.data FROM c WHERE c.type ="
+ " 'VerifiableCredential'")
.build())
.get();
// }
Assertions.assertNotNull(walletItems);
Assertions.assertEquals(0, walletItems.getItemsCount());
}
// deleteWallet() {
trinsic
.wallet()
.deleteWallet(DeleteWalletRequest.newBuilder().setWalletId(walletId).build())
.get();
// }
System.out.println("Wallets demo successful");
trinsic.shutdown();
}
}
GetWalletFromExternalIdentityRequest
Delete Item¶
Deletes an item of the wallet by its ID.
await trinsic.wallet().deleteItem({
itemId: itemId,
});
await trinsic.Wallet.DeleteItemAsync(new DeleteItemRequest {
ItemId = itemId
});
await trinsic.wallet.delete_item(request=DeleteItemRequest(item_id=item_id))
deleteResponse, err := trinsic.Wallet().DeleteItem(context.Background(),
&wallet.DeleteItemRequest{
ItemId: itemId,
})
trinsic.wallet().deleteItem(DeleteItemRequest.newBuilder().setItemId(itemId).build()).get();
DeleteItemRequest
Delete Wallet¶
Deletes a wallet, and all its credentials, permanently.
Any wallet may delete itself by passing its own ID to this call. Only Provider wallets may delete wallets other than themselves.
Wallet deletion is permanent and cannot be undone.
await trinsic.wallet().deleteWallet({
walletId: walletId,
});
await trinsic.Wallet.DeleteWalletAsync(new DeleteWalletRequest {
WalletId = walletId
});
await trinsic.wallet.delete_wallet(request=DeleteWalletRequest(wallet_id=wallet_id))
deleteWalletResponse, err := trinsic.Wallet().DeleteWallet(context.Background(),
&wallet.DeleteWalletRequest{
Account: &wallet.DeleteWalletRequest_WalletId{
WalletId: walletId,
},
})
trinsic
.wallet()
.deleteWallet(DeleteWalletRequest.newBuilder().setWalletId(walletId).build())
.get();
walletId
and didUri
.email
and didUri
.email
and walletId
.DeleteWalletRequest
. Empty payload.Search Wallet¶
Searches a wallet, returning all matching items, and a continuation_token
to paginate large result sets.
If no query
is specified, this call by default returns the first 100 items in the wallet.
let items = await trinsic.wallet().searchWallet();
var walletItems = await trinsic.Wallet.SearchWalletAsync(new());
wallet_items = await trinsic.wallet.search_wallet()
searchResponse, err := trinsic.Wallet().SearchWallet(context.Background(), &wallet.SearchRequest{})
var walletItems = trinsic.wallet().searchWallet().get();
SearchResponse
if more data is available for querySearchRequest
continuation_token
SearchRequest
Verifiable Presentation Request Spec
In the future, this endpoint will support the Verifiable Presentation Request Spec .
Advanced Search¶
The Search endpoint supports SQL queries through the query
parameter.
This allows for arbitrary query predicates, as well as more advanced functionality -- such as modifying the output format.
Schema¶
Any table name may be used in your query (we use c
here) -- it doesn't matter what it is.
Name | Type | Description |
---|---|---|
id | string | Corresponds to the item_id returned when item was inserted into wallet |
type | string | Specified via item_type when item was inserted into wallet |
data | object | The JSON object passed via item_json when item was inserted into wallet |
Note that data
is an object, not a string; thus, any of its sub-fields may be queried against.
For example, SELECT * FROM c WHERE c.data.someField = 'Hello, World!'
would match against the following JSON object inserted via InsertItem:
{
"someField": "Hello, World!"
}
Common SQL Queries¶
Paging¶
Paging uses the OFFSET
clause that takes in a value indicating how many records should be skipped in the returned query. To specify the size of the result set (page size) use the LIMIT
clause.
SELECT * FROM c OFFSET 10 LIMIT 5
Sorting¶
The optional ORDER BY
clause specifies the sorting order for results returned by the query. To control sorting order, specify ASC
or DESC
at the end; if not specified ascending order is used by default.
SELECT * FROM c ORDER BY c.credential.issued DESC
Filtering¶
The optional WHERE clause (WHERE <filter_condition>
) specifies condition(s) that the source JSON items must satisfy for the query to include them in results. A JSON item must evaluate the specified conditions to true to be considered for the result. The index layer uses the WHERE
clause to determine the smallest subset of source items that can be part of the result.
SELECT * FROM c WHERE c.name = 'Trinsic' AND c.dateCreated >= "2020-09-30T23:14:25.7251173Z"
Grouping¶
The GROUP BY
clause divides the query's results according to the values of one or more specified properties.
Examples and detailed description on working with grouped results can be found here
Additional Resources¶
You can read the full documentation on working with SQL queries on the Azure Cosmos DB website .