Tutorial: Build and Verify Trust Evidence¶
This tutorial walks you through using a Genesis Mesh SDK to build a signed trust evidence record and verify it using the public verify endpoint. The same five steps apply to all three SDKs — choose your language below.
What you will build: a TrustEvidence object that proves an authorization
decision was made between two sovereigns, and a verification check that any
third party can run without a signing key.
Prerequisites¶
A running Network Authority — see Operator Quickstart for setup steps
An admin key pair registered with the NA (
keyId+ base64-encoded seed)Language runtime:
Node.js >= 22
Go >= 1.22
.NET 8 SDK
Step 1: Install the SDK¶
npm install genesis-mesh-sdk
go get github.com/GenesisMeshLabs/sdk-go@latest
dotnet add package genesismesh-sdk-dotnet
Step 2: Create an admin client¶
Admin operations require a signing key. Pass the base64-encoded Ed25519 private key and the key ID registered with the NA. Keep the key in an environment variable — never hard-code it in source.
import { GenesisMeshClient } from "genesis-mesh-sdk";
const client = new GenesisMeshClient({
baseUrl: "http://localhost:8000",
signingKeyBase64: process.env.GM_ADMIN_KEY_B64,
keyId: process.env.GM_ADMIN_KEY_ID,
});
import (
"github.com/GenesisMeshLabs/sdk-go/genesismesh"
"os"
)
client, err := genesismesh.NewClient(genesismesh.ClientOptions{
BaseURL: "http://localhost:8000",
SigningKey: os.Getenv("GM_ADMIN_KEY_B64"),
KeyID: os.Getenv("GM_ADMIN_KEY_ID"),
})
if err != nil {
log.Fatal(err)
}
using GenesisMesh;
var client = new GenesisMeshClient(new ClientOptions
{
BaseUrl = "http://localhost:8000",
SigningKey = Environment.GetEnvironmentVariable("GM_ADMIN_KEY_B64"),
KeyId = Environment.GetEnvironmentVariable("GM_ADMIN_KEY_ID"),
});
Step 3: Build trust evidence for a trust decision¶
A TrustDecision describes an authorization outcome between two sovereigns.
Pass one to the Evidence.Build method to produce a signed TrustEvidence
record. verdict must be one of "allow", "block", "escalate", "warn".
import { TrustDecision } from "genesis-mesh-sdk";
const decision: TrustDecision = {
source_sovereign_id: "ALPHA-NA",
target_sovereign_id: "BETA-NA",
verdict: "allow",
reason: "Recognition treaty active, attestation valid",
};
const evidence = await client.evidence.build(decision);
console.log(evidence.evidence_id); // e.g. "ev-3f8a21c0"
console.log(evidence.verdict); // "allow"
console.log(evidence.issued_at); // ISO 8601 timestamp
import (
"context"
"fmt"
"github.com/GenesisMeshLabs/sdk-go/genesismesh"
)
ctx := context.Background()
decision := genesismesh.TrustDecision{
SourceSovereignId: "ALPHA-NA",
TargetSovereignId: "BETA-NA",
Verdict: "allow",
Reason: "Recognition treaty active, attestation valid",
}
evidence, err := client.Evidence.Build(ctx, decision)
if err != nil {
log.Fatal(err)
}
fmt.Println(evidence.EvidenceId) // e.g. "ev-3f8a21c0"
fmt.Println(evidence.Verdict) // "allow"
fmt.Println(evidence.IssuedAt) // ISO 8601 timestamp
using GenesisMesh;
var decision = new TrustDecision
{
SourceSovereignId = "ALPHA-NA",
TargetSovereignId = "BETA-NA",
Verdict = "allow",
Reason = "Recognition treaty active, attestation valid",
};
var evidence = await client.Evidence.Build(decision);
Console.WriteLine(evidence.EvidenceId); // e.g. "ev-3f8a21c0"
Console.WriteLine(evidence.Verdict); // "allow"
Console.WriteLine(evidence.IssuedAt); // ISO 8601 timestamp
The returned TrustEvidence object is self-contained: it includes the full
decision body, the issuer key ID, a timestamp, and the Ed25519 signature. You
can serialize it and pass it to any party that needs to verify the decision.
Step 4: Verify the evidence¶
Verification uses the public endpoint and requires no signing key. Create a second client without credentials — or reuse the same one:
const publicClient = new GenesisMeshClient({
baseUrl: "http://localhost:8000",
});
const result = await publicClient.evidence.verify({ evidence });
console.log(result.valid); // true
console.log(result.reason); // "Signature valid"
publicClient, _ := genesismesh.NewClient(genesismesh.ClientOptions{
BaseURL: "http://localhost:8000",
})
result, err := publicClient.Evidence.Verify(ctx, map[string]interface{}{
"evidence": evidence,
})
if err != nil {
log.Fatal(err)
}
fmt.Println(result.Valid) // true
fmt.Println(result.Reason) // "Signature valid"
var publicClient = new GenesisMeshClient(new ClientOptions
{
BaseUrl = "http://localhost:8000",
});
var result = await publicClient.Evidence.Verify(new Dictionary<string, object?>
{
["evidence"] = evidence,
});
Console.WriteLine(result.Valid); // True
Console.WriteLine(result.Reason); // "Signature valid"
VerifyResult always returns both fields. If Valid is false, Reason
explains why — for example, "Unknown key ID" or "Signature mismatch".
Step 5: Handle errors¶
A verdict outside the allowed set returns a 422 Validation error:
import { ValidationError } from "genesis-mesh-sdk";
try {
await client.evidence.build({
source_sovereign_id: "ALPHA-NA",
target_sovereign_id: "BETA-NA",
verdict: "trusted", // not in the allowed set
reason: "testing",
});
} catch (err) {
if (err instanceof ValidationError) {
console.error(err.code, err.message);
// "VALIDATION_ERROR verdict must be one of: allow, block, escalate, warn"
} else {
throw err;
}
}
import "errors"
_, err = client.Evidence.Build(ctx, genesismesh.TrustDecision{
SourceSovereignId: "ALPHA-NA",
TargetSovereignId: "BETA-NA",
Verdict: "trusted", // not in the allowed set
Reason: "testing",
})
var ve *genesismesh.ValidationError
if errors.As(err, &ve) {
fmt.Println(ve.Code, ve.Message)
// VALIDATION_ERROR verdict must be one of: allow, block, escalate, warn
}
try
{
await client.Evidence.Build(new TrustDecision
{
SourceSovereignId = "ALPHA-NA",
TargetSovereignId = "BETA-NA",
Verdict = "trusted", // not in the allowed set
Reason = "testing",
});
}
catch (ValidationException ex)
{
Console.WriteLine($"{ex.Code}: {ex.Message}");
// VALIDATION_ERROR: verdict must be one of: allow, block, escalate, warn
}
What’s next¶
Sub-clients — TypeScript SDK — TypeScript sub-client reference
Sub-clients — Go SDK — Go sub-client reference
Sub-clients — .NET SDK — C# sub-client reference
Operator Quickstart — set up a sovereign from scratch
Glossary — definitions for every protocol term used above