@last1id/evidence-sdk¶
Server-side SDK for syncing app evidence signals into Last1 ID as portable trust events.
Issuer is https://auth.last1.id (not the marketing site https://last1.id).
Install¶
Usage¶
import { buildMatrUsageSignal, createEvidenceClient } from "@last1id/evidence-sdk";
const client = createEvidenceClient({
issuerUrl: "https://auth.last1.id",
clientId: process.env.LAST1_CLIENT_ID!,
clientSecret: process.env.LAST1_CLIENT_SECRET!,
});
await client.validateSignals([
{
type: "community.participation.completed",
subject: { last1Sub: "00000000-0000-0000-0000-000000000001" },
occurredAt: new Date().toISOString(),
confidence: 0.91,
refs: [{ kind: "internal", id: "evt_123" }],
attributes: { channel: "video", duration_minutes: 44 },
},
]);
await client.ingestSignals([
buildMatrUsageSignal({
last1Sub: "00000000-0000-0000-0000-000000000001",
action: "session.completed",
eventId: "matr-session-123",
organizationId: "org_matr",
sessionId: "sess_9283",
attributes: { duration_minutes: 44, modality: "video" },
}),
]);
Auth and scopes¶
The SDK authenticates with HTTP Basic auth (client_id:client_secret) and calls:
POST /api/evidence/validatePOST /api/evidence/ingest
Your app client must include trust_events:write and the user must have consented to that scope.
MATR auto-ingest contract (user-driven)¶
MATR trust-building should be emitted from real user activity in MATR backend flows, not org-admin actions.
- Emit from server-side handlers whenever user usage occurs.
- Send to
POST /api/evidence/ingestviaingestSignals. - Include stable refs (
eventId) so MATR can dedupe before sending retries. - Recommended retry policy: exponential backoff (e.g. 1s, 5s, 30s, 2m) + dead-letter after max attempts.
Canonical MATR actions:
session.completedreflection.completedpeer.attestation_addedfacilitator.confirmed
These map to canonical event types:
matr.session.completedmatr.reflection.completedmatr.peer.attestation.addedmatr.facilitator.confirmed
Backend pattern (queue worker)¶
import { buildMatrUsageSignal, createEvidenceClient } from "@last1id/evidence-sdk";
const last1 = createEvidenceClient({
issuerUrl: process.env.LAST1_ISSUER_URL!,
clientId: process.env.LAST1_CLIENT_ID!,
clientSecret: process.env.LAST1_CLIENT_SECRET!,
});
export async function onMatrUsageEvent(evt: {
last1Sub: string;
action: "session.completed" | "reflection.completed" | "peer.attestation_added" | "facilitator.confirmed";
eventId: string;
organizationId?: string;
sessionId?: string;
attributes?: Record<string, unknown>;
}) {
const signal = buildMatrUsageSignal(evt);
await last1.ingestSignal(signal);
}