Skip to content

@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

npm install @last1id/evidence-sdk@0.1.0

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/validate
  • POST /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/ingest via ingestSignals.
  • 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.completed
  • reflection.completed
  • peer.attestation_added
  • facilitator.confirmed

These map to canonical event types:

  • matr.session.completed
  • matr.reflection.completed
  • matr.peer.attestation.added
  • matr.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);
}