cd /news/large-language-models/build-an-execution-receipt-wrapper-f… · home topics large-language-models article
[ARTICLE · art-61558] src=dev.to ↗ pub= topic=large-language-models verified=true sentiment=· neutral

Build an Execution Receipt Wrapper for LLM API Calls

A developer proposes an execution receipt wrapper for LLM API calls that preserves operational metadata without logging full prompts or responses. The receipt includes fields like request ID, latency, validation outcome, and fallback status, enabling investigation of production responses while minimizing data exposure. The approach uses an append-oriented, versioned store separate from general-purpose logs.

read2 min views1 publishedJul 16, 2026

Model integrations are easy to instrument badly.

Logging every prompt creates unnecessary data exposure. Logging only the model name leaves too little evidence when a production response needs investigation.

An execution receipt offers a middle path: preserve operational metadata without copying the full interaction into a general-purpose log.

What belongs in the receipt?

Useful fields include:

request and task identifiers;

prompt, policy, and schema versions;

endpoint alias;

start time and latency;

usage measurements;

validation outcome;

fallback or retry status.

Application request

Redaction and classification

Model endpoint

Output validation

Execution receipt store

Teams evaluating model endpoints for this architecture can place VectorEngine behind the same application-owned wrapper and receipt format.

Disclosure: this article includes an external referral link for readers who want to explore the platform.

TypeScript-style pseudocode

type Receipt = {

requestId: string;

task: string;

promptVersion: string;

endpointAlias: string;

startedAt: string;

latencyMs?: number;

contractPassed?: boolean;

fallbackUsed: boolean;

status: "started" | "completed" | "failed";

};

async function invokeWithReceipt(input: unknown, ctx: Context) {

const started = Date.now();

const receipt: Receipt = {

requestId: ctx.requestId,

task: ctx.task,

promptVersion: ctx.promptVersion,

endpointAlias: ctx.endpointAlias,

startedAt: new Date(started).toISOString(),

fallbackUsed: false,

status: "started"

};

try {

const result = await invokeEndpoint(input, ctx.endpointAlias);

receipt.latencyMs = Date.now() - started;
receipt.contractPassed = validateOutput(result);
receipt.status = "completed";

await appendReceipt(receipt);
return result;

} catch (error) {

receipt.latencyMs = Date.now() - started;

receipt.status = "failed";

await appendReceipt(receipt);
throw error;

}

}

This example intentionally excludes raw input and output. If investigation requires content access, store it under a separate retention and authorization policy rather than embedding it in every receipt.

Receipts should also be append-oriented and versioned. Editing old records in place makes later reconstruction harder.

The goal is modest: retain enough evidence to understand how a model-backed feature executed, while collecting no more content than the workflow requires.

── more in #large-language-models 4 stories · sorted by recency
── more on @vectorengine 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/build-an-execution-r…] indexed:0 read:2min 2026-07-16 ·