Skip to main content

Replay a Business Transaction

POST /replay
Implemented in packages/api/src/routes/replay.ts. Validates only that businessTransactionId is present (unlike execute/verify/receipt, this route does not check it’s a well-formed UUID), then calls application.replay(businessTransactionId).
curl -X POST http://localhost:3000/replay \
  -H "Content-Type: application/json" \
  -d '{ "businessTransactionId": "b6f1c8de-1a2b-4c3d-8e9f-0a1b2c3d4e5f" }'
Response 200
interface ReplayResult {
  businessTransactionId: string;
  trustRecordHash: string;
  verified: boolean;
}
Response 400
{ "error": "businessTransactionId is required." }
What POST /replay actually does is not what the replay package does. ExecutionTrustApplication.replay (packages/runtime/src/ExecutionTrustApplication.ts) is:
async replay(businessTransactionId: string) {
  const trustRecord = await this.trustRecords.findByTransactionId(businessTransactionId);
  if (!trustRecord) throw new Error("Execution Trust Record not found.");
  const verified = await this.crypto.verify(trustRecord);
  return { businessTransactionId, trustRecordHash: trustRecord.trustRecordHash, verified };
}
This calls VerificationCrypto.verify from @parmana/crypto — the exact same hash-integrity check used by POST /verify. It never imports or calls anything from the replay package.The replay package’s ReplayEngine.replay() (packages/replay/src/ReplayEngine.ts) is a real, separately-implemented engine that re-evaluates the recorded Policy against the recorded signals via PolicyEngine.evaluate, builds a replayedDecision, and compares it against the recordedDecision to produce a richer result:
interface ReplayEngineResult {
  recordedDecision: Decision;
  replayedDecision: Decision;
  matches: boolean;
  replayedAt: Date;
}
That engine — along with ReplayBuilder, ReplayVerifier, ReplayPipeline, ReplayExecutor, and ReplayPlan — is exported from packages/replay/src/index.ts but is not wired into packages/api at all. There is no HTTP route that exercises deterministic decision replay today; POST /replay only re-verifies the trust record’s hash, which is functionally redundant with POST /verify.
Concepts → Replay documents the ReplayResult shape that POST /replay actually returns ({ businessTransactionId, trustRecordHash, verified }), so the concept and this route are consistent with each other. The gap is specifically between both of those and the unused replay package engine described above.

SDK equivalents

const replay = await client.replay(businessTransactionId);
Both SDKs’ replay() call POST /replay and type their return as ReplayResult matching the flat { businessTransactionId, trustRecordHash, verified } shape above — they mirror the route as implemented, not the replay package’s richer decision-comparison result.

Replay (concept)

What replay is meant to guarantee.

replay package

The unused deterministic decision-replay engine.

Verify

The endpoint this route’s logic actually duplicates.

Deterministic Replay Guide

Working with replay today, and what it doesn’t yet check.