Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions agents/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ The agent lives on your signed-in profile by default. Ask for a dedicated spend
## Use it where you work

- **Chat and jobs on Proofable.** Chat now, or start a [job](/jobs) for background and scheduled work.
- **Any app or runtime.** Talk to it with one call from your app, your server, or another runtime. Nothing to deploy. [Talk from any app](/agents/talk-to-an-agent)
- **Any MCP client.** Load the same agent with `npx -y @proofable/sdk mount <agentId> --apply cursor`.
- **Your servers.** Point the runtime at the same endpoint with an [access key](/deployment/access-keys), or deploy to a [private cloud](/deployment/private-cloud).
- **Other apps and marketplaces.** Each agent has a public card that others can check before they trust it. [Discover agents](/agents/named-agent-card)
Expand All @@ -45,6 +46,7 @@ Keep your model, runtime, and enterprise sign-in such as Okta. Proofable keeps t
| Where the agent runs | What Proofable provides |
|---|---|
| Chat and jobs on Proofable | Enforces permissions, tool access, and proof checks |
| Your app, calling the agent | Runs the turn as the agent and checks every tool call against its permission |
| MCP clients | Loads the agent's rules and context. Start a new session after you mount. |
| Your workers and backends | Returns the permission bundle for your code to enforce |

Expand Down
102 changes: 102 additions & 0 deletions agents/talk-to-an-agent.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
---
title: Talk to your agent from any app
sidebarTitle: Talk from any app
description: Your agent runs on Proofable. Any app, server, or runtime talks to it with one call, inside the limits you signed, and every answer cites the records it read.
icon: comments
---

Your agent runs on Proofable, so there is nothing to deploy and no machine to keep. Any app, server, or runtime talks to it with one call. It answers as itself, inside the limits you signed, and cites the records it read.

## One call

```javascript
import { ProofableClient } from '@proofable/sdk';

const client = new ProofableClient({ apiKey: process.env.PROOFABLE_ACCESS_KEY });

const turn = await client.agentChat({
agentId: 'my-agent',
messages: [{ role: 'user', content: 'Summarize this week for the client.' }],
onEvent: (type, data) => {
if (type === 'answer.delta') process.stdout.write(data.text);
},
});

turn.answer; // the agent's answer
turn.citations; // the records it read
turn.credits; // what the turn spent
```

Sign the client in with an [access key](/deployment/access-keys) on a server, or with the signed-in person's session in a browser. Never ship an access key in browser code.

## What happens on each turn

1. Proofable finds the [permission](/agents/agent-delegation) you signed for the agent. No active permission from your account, no turn.
2. The turn runs as the agent: its own instructions and skills from its [identity](/agents/agent-identity), and the connected apps you bound to it.
3. Every tool call is checked against the permission before it runs, read again for each call. Revoke the permission and the next call stops, in every app that talks to the agent.
4. The answer comes back with the records the agent read. Each one opens at `proofable.me/proof/<qHash>`, so anyone you share it with can check where the answer came from.

## Over HTTP

`POST https://api.proofable.me/api/v1/agent/chat/turn` with `Authorization: Bearer <token>` streams the turn as Server-Sent Events.

```bash
curl -N https://api.proofable.me/api/v1/agent/chat/turn \
-H "Authorization: Bearer $PROOFABLE_ACCESS_KEY" \
-H "Content-Type: application/json" \
-d '{"agentId":"my-agent","messages":[{"role":"user","content":"What changed today?"}]}'
```

| Field | What it does |
|---|---|
| `agentId` | Run the turn as this agent. Omit it to run as yourself. |
| `agentWallet` | The agent's account, when two of your agents share an id |
| `messages` | The conversation, `user` and `assistant` turns, ending with the user |
| `systemPrompt` | Context from your app. The agent reads it as data, after its own instructions. |
| `model` | `default` or `advanced`. With `provider`, that provider's model id. |
| `provider`, `providerSecretProofQHash` | Run on your own model key from the vault instead of hosted inference |

The stream sends `turn.start`, `answer.delta` as the answer arrives, `tool.start` and `tool.result` for each call, and ends with one `final` event:

```json
{
"outcome": "succeeded",
"answer": "…",
"citations": [{ "qHash": "0x…", "title": "Chapter 1", "facet": "memory", "visibility": "public" }],
"agent": { "agentId": "my-agent", "agentWallet": "0x…", "identityQHash": "0x…", "delegationQHash": "0x…" },
"credits": { "spent": 2 }
}
```

A request Proofable refuses never opens the stream. It answers JSON with the reason:

| Status | Code | Why |
|---|---|---|
| 401 | `AUTH_REQUIRED` | No session, OAuth token, or access key |
| 402 | `INSUFFICIENT_CREDITS` | Not enough credits for a hosted turn |
| 403 | `AGENT_DELEGATION_REQUIRED` | No active permission from your account to this agent |
| 403 | `ADVANCED_REQUIRES_PRO` | Advanced runs on paid plans |

## What it costs

A hosted turn spends credits from the account that calls it, by the tokens it used and the model that served them, the same rate as a [job](/jobs) step. A turn on your own model key spends no platform credits. See [pricing](/pricing).

Read your balance and spend at any time, by line and by day:

```javascript
const { credits, usage } = await client.getUsage({ from: '2026-11-01', to: '2026-11-30' });
usage.summary.debitedByDay; // { '2026-11-01': 14, … }
```

Over HTTP it is `GET /api/v1/profile/usage?from=YYYY-MM-DD&to=YYYY-MM-DD` with the same token. In an MCP client, `proofable_context` carries the balance.

## Other ways to reach the same agent

- **In an MCP client.** `npx -y @proofable/sdk mount my-agent --apply claude` loads the agent into Claude, Cursor, Codex, Hermes, OpenClaw, or OpenCode. [Connect agent context](/agents/runtime-mount)
- **As background work.** Start a [job](/jobs) for scheduled or long work, on an isolated computer when it needs one.

## Related

- [Agent permissions](/agents/agent-delegation)
- [Agent identity](/agents/agent-identity)
- [Import an agent](/agents/import)
2 changes: 1 addition & 1 deletion docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@
"pages": [
{
"group": "Agents",
"pages": ["mcp/guarded-action", "agents/agent-delegation", "agents/agent-identity", "agents/import", "agents/named-agent-card", "agents/team-agents", "agents/runtime-mount"]
"pages": ["mcp/guarded-action", "agents/talk-to-an-agent", "agents/agent-delegation", "agents/agent-identity", "agents/import", "agents/named-agent-card", "agents/team-agents", "agents/runtime-mount"]
},
{
"group": "Proofs",
Expand Down
232 changes: 232 additions & 0 deletions openapi/public-api.json
Original file line number Diff line number Diff line change
Expand Up @@ -3971,6 +3971,108 @@
}
}
},
"/api/v1/profile/usage": {
"get": {
"operationId": "getProfileUsage",
"summary": "Read your credits and spend, by line and by day",
"tags": [
"Profile"
],
"parameters": [
{
"name": "from",
"in": "query",
"required": false,
"schema": {
"type": "string",
"format": "date"
},
"description": "First UTC day of the period (YYYY-MM-DD)."
},
{
"name": "to",
"in": "query",
"required": false,
"schema": {
"type": "string",
"format": "date"
},
"description": "Last UTC day of the period (YYYY-MM-DD)."
},
{
"name": "appId",
"in": "query",
"required": false,
"schema": {
"type": "string"
},
"description": "Only spend recorded under this app or namespace."
},
{
"name": "limit",
"in": "query",
"required": false,
"schema": {
"type": "integer",
"minimum": 1,
"maximum": 500
},
"description": "Most events returned, newest first (default 500)."
}
],
"responses": {
"200": {
"description": "Balance, events and summary"
},
"400": {
"description": "Invalid period"
},
"401": {
"description": "Authentication required"
},
"403": {
"description": "Forbidden",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
}
},
"404": {
"description": "Not found",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
}
},
"429": {
"description": "Rate limited",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
}
},
"500": {
"description": "Server error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
}
}
}
}
},
"/api/v1/profile/gates/discoverable": {
"get": {
"operationId": "listDiscoverableGates",
Expand Down Expand Up @@ -4731,6 +4833,136 @@
}
}
}
},
"/api/v1/agent/chat/turn": {
"post": {
"operationId": "streamAgentChatTurn",
"summary": "Talk to an agent: run one chat turn as it, streamed as Server-Sent Events",
"description": "Runs one turn on the hosted agent runtime. With agentId the turn runs as that agent: its instructions and skills, under the delegation you signed, every tool call checked against it. The final event carries the answer, the records it read as citations, and the credits it spent. Nothing to deploy: call it from any app or runtime with a session, an OAuth token or a profile access key.",
"tags": [
"Agents"
],
"parameters": [],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"messages"
],
"properties": {
"agentId": {
"type": "string",
"description": "Run the turn as this agent, under the delegation the caller signed for it."
},
"agentWallet": {
"type": "string",
"description": "The agent's account, when two of the caller's agents share an agentId."
},
"messages": {
"type": "array",
"description": "The visible conversation; the last message is from the user.",
"items": {
"type": "object",
"required": [
"role",
"content"
],
"properties": {
"role": {
"type": "string",
"enum": [
"user",
"assistant"
]
},
"content": {
"type": "string"
}
}
}
},
"model": {
"type": "string",
"description": "A hosted tier (\"default\", \"advanced\") or, with a provider, that provider's model id. Defaults to \"default\"."
},
"provider": {
"type": "string",
"description": "Omit for hosted inference; name a provider to run on your own key."
},
"providerSecretProofQHash": {
"type": "string",
"description": "The vault secret holding your provider key."
},
"systemPrompt": {
"type": "string",
"description": "Context from your app. With agentId it follows the agent's own instructions, as data."
},
"responseMode": {
"type": "string",
"enum": [
"agent",
"plan"
]
},
"turnId": {
"type": "string"
}
}
}
}
}
},
"responses": {
"200": {
"description": "text/event-stream in the agent-turn-events/1 contract"
},
"400": {
"description": "Invalid turn request"
},
"401": {
"description": "Authentication required"
},
"402": {
"description": "Not enough credits for a hosted turn"
},
"403": {
"description": "No active delegation for this agent, or Advanced without a paid plan"
},
"404": {
"description": "Not found",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
}
},
"429": {
"description": "Rate limited",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
}
},
"500": {
"description": "Server error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
}
}
}
}
}
}
}
Loading