Reports and receipts
Read a run's report JSON (findings, sections, evidence and sources), use evidenceFor in the SDK, download the JSON export and read the settlement receipt.
When a run ends, its report is in the run and its charge is in the receipt. This page explains the report JSON your code receives, how findings point to evidence, how the SDK normalises every report kind, the JSON export and the settlement receipt. It is for developers who process AGENTEX results in their own systems. For what the report means to a reader, see How reports work and Evidence.
Where the report is#
GET /v1/runs/{id} returns { run, events }. Once the run has a report, run.output holds it; before that it is null. A succeeded or partial run has a report. A failed run may have one that records its errors, or none, so check run.output before reading it.
In the SDK, getReport(runId) reads the run and returns the typed report; it throws conflict / report_unavailable if there is no report yet.
The report JSON#
Every report names its format in schemaVersion:
schemaVersion | Produced by |
|---|---|
agentex.workflow.v1 | Research workflows (most catalog agents) |
agentex.token-research.v1 | Token Researcher |
agentex.transaction-inspection.v1 | Transaction Inspector |
agentex.solana-transaction-inspection.v1 | Solana Transaction Inspector |
agentex.deployer-investigation.v1 | Deployer Investigator |
agentex.wallet-analysis.v1 | Wallet Analyst |
agentex.watchtower-window.v1 | Watchtower monitor windows |
Fields common to every kind:
| Field | Meaning |
|---|---|
status | complete, partial or failed. This is the report's own status, separate from the run status. |
generatedAt, agentVersion, manifestHash | When the report was produced, and the exact agent version that produced it. |
input | The input the run was accepted with. |
evidence | Every recorded read, with its source and the block or slot it was read at. |
limitations | What this agent does not cover, as plain sentences. |
errors | What went wrong, if anything, each with a message. |
usage | Reads used against the version's limit, elapsed time and model usage. |
Research workflow reports put their findings in sections. Each section has id, title, status (complete, partial, skipped or failed), reason and findings. Each finding has a code, a label, a status and evidenceIds:
observed: avalueread from the cited evidence;from-input: avaluetaken from your input, with no evidence;unknownornot-run: no value, with areason.
Workflow reports also carry requiredSections, the executed steps, and a presentation with the report's archetype and headline, plus signals, datasets and coverage where the agent declares them.
Other report kinds have a top-level findings list, each with code, message and evidenceIds, alongside their own typed sections (for example Token Researcher's metadata, contract and controls observations). Agents with an AI-assisted summary add analysis: when its status is completed, analysis.findings holds claims with claim, evidenceIds and confidence (supported or uncertain).
This is part of a real research workflow report (Solana Token Safety Check, from its public saved example), abridged:
{
"schemaVersion": "agentex.workflow.v1",
"status": "complete",
"sections": [
{
"id": "authorities",
"title": "Authorities and extensions",
"status": "complete",
"reason": null,
"findings": [
{
"code": "mint-authority",
"label": "Mint authority",
"status": "observed",
"value": "8Jornc27vtAYPkwDzsZVgLQchAYyC8nD7aCNPCDV8Qk2",
"evidenceIds": ["ev-799328de2dbe4e9047e43171557b60fd", "ev-eedd7cd0fbcd7097e3c0079c6bbfd23b", "ev-eb5de04e0fa0b3c8ce12e3af5f901aaa"]
}
]
}
],
"evidence": [
{
"id": "ev-eb5de04e0fa0b3c8ce12e3af5f901aaa",
"tool": "solana.token-safety@0.1.0",
"source": { "kind": "rpc", "provider": "solana-configured-rpc", "method": "getMultipleAccounts", "documentationUrl": "https://solana.com/docs/rpc" },
"chain": "solana",
"snapshot": { "kind": "solana-slot", "slot": "450789376", "commitment": "confirmed", "exactness": "lower-bound" },
"finality": "confirmed-lower-bound",
"completeness": "complete-for-request",
"request": ["..."],
"result": { "...": "..." },
"contentHash": "..."
}
]
}Evidence items#
| Field | Meaning |
|---|---|
id | ev- followed by 32 hex characters, derived from the item's content. Findings cite these ids. |
tool, capability | The tool and capability that made the read. |
source | kind (rpc, http or offline), provider, method and documentationUrl. |
chain, scope | The chain read and the subjects (addresses, mints) the read was about. |
snapshot | Where the read is pinned: an EVM block (blockNumber, blockHash), a Solana slot (slot, commitment), a web retrieval time, or null for reads with no position, such as a genesis hash. |
finality, canonicality | How settled that position was, and whether it was rechecked at completion. |
completeness | complete-for-request, truncated, empty-result, unavailable or error. |
request, result | The raw request and response. |
contentHash | A hash of result, so you can check the stored response has not changed. |
trust, privacy | Whether the data is chain state, a provider's assertion or untrusted third-party web content. |
Read reports with the SDK#
getReport returns a ResearchReport that has the same shape for every kind: all findings in one findings list (workflow section findings included, deterministic findings first, AI-assisted claims last with origin: 'model'), evidence with block and slot flattened from the snapshot, and sources grouping evidence by provider.
import { ASSETS, createBuyerClient, evidenceFor } from 'agentex-creator-sdk/buyer';
const agentex = createBuyerClient({ apiKey: process.env.AGENTEX_API_KEY!, assetId: ASSETS.SOL });
const report = await agentex.getReport('<runId>');
console.log(report.kind, report.status, report.headline);
for (const finding of report.findings) {
const label = finding.origin === 'model' ? `${finding.text} [AI-assisted, ${finding.confidence}]` : finding.text;
console.log(`${finding.section ?? '-'}: ${label}`);
for (const item of evidenceFor(report, finding)) {
console.log(` ${item.id} ${item.source.provider} ${item.source.method} at ${item.slot ?? item.block ?? 'no pinned position'} (${item.completeness})`);
}
}
for (const source of report.sources) console.log(`${source.provider}: ${source.methods.join(', ')}`);
for (const limitation of report.limitations) console.log(`Limitation: ${limitation}`);evidenceFor(report, finding)returns the evidence items the finding cites, in citation order. It also accepts a plain list of evidence ids.finding.statusisobserved,from-input,unknownornot-runfor workflow findings,rulefor deterministic findings of other kinds, andmodelfor AI-assisted claims.report.rawis the report exactly as stored, for kind-specific fields.readReport(output)fromagentex-creator-sdk/reportdoes the same normalisation on any stored report, with no network access.
The JSON export#
GET /v1/runs/{id}/export (scope runs:read) returns the canonical export of a run that has a report:
curl -s -H "Authorization: Bearer $AGENTEX_API_KEY" https://agentex.sh/v1/runs/<runId>/export -o agentex-run.json- The body is
{ "run": { ... }, "version": { ... }, "events": [ ... ] }: the run with its report, the immutable agent version it ran (manifest and hash), and the run's events. - The
X-Agentex-Artifact-Idheader names the stored copy. AGENTEX keeps it privately for 30 days; after that a new request generates it again. - Before the run has a report the call returns
409"This run does not have a report to export yet." - In the SDK:
getResult(runId)returns{ artifactId, run, version, events }. In the CLI:agentex-buyer result --run <runId> --out result.json.
CSV, Markdown and the readable HTML report, and public share links, are created from the run's page on the website while signed in. API keys cannot create them.
The settlement receipt#
GET /v1/runs/{id}/receipt (scope billing:read) returns the receipt of one of your paid runs, as a JSON download (agentex-receipt-<runId>.json).
| Field | Contents |
|---|---|
schema | agentex.settlement-receipt.v1 |
runId, environment, issuedAt | The run, the environment and when this receipt was issued |
quote | id, contractHash, expiresAt, resultPolicy, resultContract, priceRevision |
listing | listingId, agentVersionId, agentVersionHash |
input | The accepted input |
payment | assetId, currencyLabel, decimals, and chainId for ETH |
feeSplit | grossCreatorFeeAtomic, feeBps, platformFeeAtomic, creatorCreditAtomic, maxExecutionChargeAtomic, maximumBuyerDebitAtomic |
billing | status, settlement (with outcome and chargedAtomic), read counts and pendingReason |
modelCost | The AI analysis cost line, or null for agents without one |
buyer | Your account's wallet address |
A run with no paid quote returns 404 "This run has no settlement receipt."
In the SDK, getReceipt(runId, { quote, waitForSettlement: true }) gives a smaller receipt built from billing, with the charge already formatted:
const receipt = await agentex.getReceipt(runId, { quote, waitForSettlement: { timeoutMs: 120_000 } });
console.log(receipt.status, receipt.outcome, receipt.charged, receipt.payment.label); // 'settled' 'succeeded' '0.0021 SOL' 'SOL on Solana'
console.log(receipt.fees); // { creatorFeeAtomic, platformFeeAtomic, executionChargeAtomic }Passing the quote lets the receipt name the payment asset without an extra request and report the quote maximum as maximumDebitAtomic.