RAVEN. / integrate

Integrate Raven (customer stranger path)

One coherent path for a new integrator: obtain evidence, supply your own pinned trustedKeys, call verifyReceiptV1ForSubject with the exact expected subject, keep axes separate, and apply your policy. Raven never authorizes an action.

1. Obtain

Primary customer path: POST /receipt/v1 with your API key. Returns a signed receipt-v1 deliverable. POST /verify is legacy official-attestation v2 compatibility only.

2. Package status (public truth)

3. Pin (trust decision)

Supply Ed25519 key bytes yourself as trustedKeys (caller-controlled pin array). Cross-check site footer, repos, and GET /pubkey. /pubkey is discovery only, never a trust root. Never wire trustedKeys from fetch("/pubkey").

4. Verify receipt-v1 axes (real verifier shape)

Call verifyReceiptV1ForSubject(receipt, expectedSubject, options). Keep answers separate — never collapse into Raven authorization:

  1. valid — integrity/signature
  2. keyTrusted — caller-pin match
  3. stale — freshness (!stale required)
  4. subjectMatches === true — exact expected subject (chain + mintAddress + tokenProgramAddress)
  5. rulesStatus === "supported_valid" — exact string (not "ok", not a boolean)

5. Legacy v2

Legacy official-attestation v2 uses POST /verify, domain raven-official-attestation, and fields like verdict/replayHash/officialAttestationHash. Vector: /receipt-test-vector.json (family legacy-official-attestation-v2). Not for receipt-v1 verifiers. receipt-v1 is the current customer path; legacy v2 is compatibility only — not both current.

6. MCP

Local MCP (npx raven-verify-mcp) is unsigned developer preview — not a signed receipt-v1 deliverable. Use hosted POST /receipt/v1 for signed evidence.

7. Real verifier example

Timestamps must be ISO-8601 with Z (or an explicit offset). Never unzoned local times. Caller supplies the pin; do not invent a one-boolean Raven gate.

import { verifyReceiptV1ForSubject } from "raven-receipt-verifier";

// Caller-controlled pin (independently obtained). NOT fetch("/pubkey").
const trustedKeys = [
  process.env.RAVEN_PINNED_PUBKEY
  // e.g. "MCowBQYDK2VwAyEASGJt4Ilx2Z6g0BVC1VQIfaUcV0nr8WB1J45/8vfje6w="
];

const receipt = await postReceiptV1({ mintAddress, tokenProgramAddress });

const result = verifyReceiptV1ForSubject(
  receipt,
  {
    chain: "solana-mainnet",
    mintAddress,
    tokenProgramAddress, // all three required
  },
  { now: new Date(), trustedKeys },
);

// CUSTOMER POLICY (not a Raven verdict / pass / safe / approved):
const proceed =
  result.valid &&
  result.keyTrusted &&
  !result.stale &&
  result.subjectMatches === true &&
  result.rulesStatus === "supported_valid";

CUSTOMER POLICY is your authorization gate over the five independent axes — not Raven saying pass/safe/verified. Axes stay separate: never gate on valid alone, never substitute verdict === "pass", never drop subjectMatches / token-program binding / rulesStatus === "supported_valid".