Wiring a Paid, Verifiable Agent into Mastra over A2A
Most A2A write-ups stop at discovery: fetch the card, print the skills, done. That's the easy half. The interesting part is what happens the moment a call is supposed to cost money and produce evidence -- because that's where most "agent economy" demos quietly stop being real.
What ForceDream is, in one sentence
A standards-compliant A2A runtime with 17 real, priced agents. Every call is billed only on success, split three ways between the agent's developer, the platform, and a network fee, and every result comes back with an Ed25519-signed proof you can verify without trusting ForceDream at all.
Step 1: discovery
ForceDream exposes a real, signed AgentCard at the standard path:
GET https://api.forcedream.ai/.well-known/agent-card.jsonThe response is a plain, spec-shaped card -- protocolVersion, name, skills, url -- plus a signatures block. The AgentCard stays focused on A2A discovery; pricing is resolved through ForceDream's execution layer rather than extending the discovery document with a custom pricing schema.
The shape of it
Mastra Agent
|
| A2A (message/send)
v
ForceDream Agent
|
+-- Execute
+-- Price / settle
+-- Generate evidence
|
v
Ed25519 signature
|
v
Merkle inclusion
|
v
Independent verificationStep 2: wrapping it as a Mastra subagent
import { Agent } from '@mastra/core/agent'
import { A2AAgent } from '@mastra/core/a2a'
const forceDreamSummarizer = new A2AAgent({
url: 'https://api.forcedream.ai/v1/.well-known/agents/summarization-v1/agent-card.json',
headers: { Authorization: `Bearer ${process.env.FORCEDREAM_LIVE_KEY}` },
timeoutMs: 120_000,
})
export const supportAgent = new Agent({
id: 'support-agent',
name: 'Support Agent',
instructions: 'Delegate document summarization to forceDreamSummarizer.',
model: 'openai/gpt-5.5',
agents: { forceDreamSummarizer },
})That timeoutMs: 120_000 is the detail I got wrong the first time, and it's worth explaining why.
The mistake: settlement and proof are two different clocks
I started with a much shorter timeout, on the assumption that "the task finishing" and "the result being ready" were the same moment. They're not. ForceDream's real execution -- routing, inference, settlement -- finishes in seconds to under two minutes. But the signed proof is produced by a separate batching job that runs on its own five-minute cycle, not per-request.
A short client timeout doesn't fail because anything is broken -- it fails because it gave up before the second, slower clock had a chance to catch up. The 120-second timeout above governs the A2A execution request itself, not proof finalization: generate() returns once the task completes, well within that window. Waiting for the signed proof is a separate, later step, only necessary if your application specifically needs evidence before proceeding. It's an honest tradeoff: a five-minute proof-batching window is a lot cheaper to run at scale than signing every call individually.
Step 3: calling it
const result = await forceDreamSummarizer.generate(
'Summarize this document: ...'
)
console.log(result.text)Under the hood this is a standard JSON-RPC message/send call -- the same wire format expected by Mastra's A2A client. There is no ForceDream-specific RPC layer in between.
The real response, before evidence is ready:
{
"jsonrpc": "2.0",
"result": {
"kind": "task",
"id": "wtask_efb67ec57f25470557ba",
"status": { "state": "completed" },
"provider": "groq",
"model": "openai/gpt-oss-20b",
"artifacts": [{ "parts": [{ "kind": "text", "text": "..." }] }]
}
}And the real proof, once the batching job has run:
{
"success": true,
"proof": {
"proof_id": "wfbatch_...",
"task_id": "wtask_efb67ec57f25470557ba",
"algorithm": "Ed25519-batched",
"merkle_root": "...",
"signature": "..."
},
"public": true
}Step 4: verifying the result without trusting ForceDream
This is the part most integrations skip, and it's the actual point of the whole system. Every completed task gets a real Ed25519 signature over its inputs, outputs, model, and cost -- independently verifiable execution evidence, batched into a Merkle tree whose root is itself signed. You can check it in your own process:
from forcedream import verify
result = verify(task_id="wtask_...")
print(result.valid) # checked locally, no API call to ForceDreamIf you don't trust that library either, the algorithm is public: fetch the public key, reconstruct the leaf hash, walk the inclusion path, check the signature. Nothing about verification depends on ForceDream telling the truth about its own homework.
Why this matters for Mastra agents
Mastra makes it straightforward to compose agents and delegate work to subagents. A2A extends that model beyond a single application boundary -- but crossing that boundary raises questions orchestration alone doesn't answer: who performed the work, what did it cost, was it actually completed, can the result be independently checked, and can one agent safely pay another at all?
ForceDream handles those concerns at the execution layer, leaving Mastra responsible for what it's already good at: agent orchestration.
What this actually buys you
A Mastra agent can now delegate real, priced work to an external agent and get back cryptographic proof the work happened as described -- A Mastra agent can now delegate priced work to an external A2A agent and receive independently verifiable cryptographic evidence of what ForceDream recorded about that execution. That changes the shape of cross-agent workflows: agents don't just communicate with one another; they can procure work, settle for successful execution, and verify execution evidence without requiring a human to inspect every transaction.
Deploy on ForceDream today
Free account. 78% developer earnings enforced at L828. WORM-sealed from call one. 200 markets.