Datoka API

Signed receipts for your API exchanges.

# Datoka API: from captured response to verifiable handoff

Use a paid receipt when a recipient needs Datoka's signed commitment to your
API exchange declaration: handing off an API response, retaining the input to
a decision, or checking an archive later. Use a local log when that is enough.
Price: 0.002 USDC on Base per receipt. Preparation and verification are free.
No Datoka account or API key is needed for public operations.

## Choose a connection

| Route | Free operations | Purchase |
| --- | --- | --- |
| Direct HTTP API | Available | Recoverable x402 example below |
| Direct MCP /mcp | Available | Requires a client sending params._meta["x402/payment"] |
| Smithery REST Connect | Keys, preparation and price offer tested | Payment metadata transport not validated; use direct HTTP |

Direct MCP URL: https://datoka-api.bhazarstudio.workers.dev/mcp
Transport: Streamable HTTP. HTTP API schema: /openapi.json.
Tools: prepare_api_exchange, issue_api_receipt, verify_api_receipt,
get_api_public_keys. Discovery alone does not give an agent a funded wallet.
The direct payment client never sends your Smithery token to Datoka.

## 1. Try without a wallet

Requires Node.js 24+. On PowerShell use curl.exe instead of curl.
Download the standalone example and its manifest:

```sh
curl --fail https://datoka-api.bhazarstudio.workers.dev/examples/0.3.9/first-receipt.mjs -o first-receipt.mjs
curl --fail https://datoka-api.bhazarstudio.workers.dev/examples/0.3.9/manifest.json -o example-manifest.json
node --input-type=module -e "import fs from 'node:fs'; import crypto from 'node:crypto'; const m=JSON.parse(fs.readFileSync('example-manifest.json')); if(crypto.createHash('sha256').update(fs.readFileSync('first-receipt.mjs')).digest('hex')!==m.sha256)process.exit(1);"
node first-receipt.mjs preview
curl --fail -X POST https://datoka-api.bhazarstudio.workers.dev/v1/operations/get_api_public_keys -H "Content-Type: application/json" --data "{}" -o trusted-keys.json
node first-receipt.mjs init ./private-purchase trusted-keys.json
node first-receipt.mjs check ./private-purchase
```

These commands do not pay or issue a receipt. The example captures a real local
HTTP exchange with an explicitly synthetic response. Hashes come from captured
bytes; they are not invented. For a real integration use captureExchange from
the versioned SDK, save captured.event as event.json and pass it after the trust
file to init. Keep the original response bytes yourself. See /quickstart.
A manifest from this same HTTPS site establishes file consistency, not independent
publisher identity. Review the example before giving it signing access.
Confirm issuer public keys through your trust policy before buying or verifying;
a downloaded keys file alone only establishes trust in this HTTPS site.

## 2. Buy once, only with an approved budget

Supply DATOKA_BUYER_PRIVATE_KEY through your secret manager to a dedicated EOA
signer holding native USDC on Base. Never paste the key into a prompt, MCP tool,
public connector configuration or source file. Hardware wallet users should
integrate a signer; never export the hardware wallet's private key.

```sh
node first-receipt.mjs prepare ./private-purchase
node first-receipt.mjs resume ./private-purchase --approve-payment
node first-receipt.mjs verify ./private-purchase
```

prepare validates the destination, network and maximum 0.002 USDC, signs locally
and persists pending.json without submitting payment. Run resume promptly because
the authorization is short-lived. Only resume --approve-payment can pay.
After timeout, rerun resume with the SAME directory. Never replace the event,
idempotency key or payment authorization. Once receipt.json exists, resume checks
it locally without another payment. Do not delete a pending purchase to retry.
This per-purchase cap is not an application-wide budget; enforce your total budget.
See /first-receipt for locks, interruptions and filesystem limitations.

## 3. Hand off the receipt

```sh
node first-receipt.mjs export ./private-purchase evidence.json
```

This offline command checks the saved purchase and exports only the receipt and
declaration. To share the captured response as well, explicitly choose:

```sh
node first-receipt.mjs export ./private-purchase evidence-with-response.json --include-response
```

Only share response content with an authorized recipient. No wallet signature,
payment authorization, private key or raw target URL is included by the exporter.
The receipt contains the buyer wallet scope. The private purchase directory
stays with the buyer. Exports refuse to overwrite files. An imported event without
saved response bytes uses evidence.mjs pack with the separately retained raw file.

## 4. The recipient verifies offline, free

Download the SDK, verification script and manifest before going offline:

```sh
curl --fail https://datoka-api.bhazarstudio.workers.dev/sdk/0.3.9/datoka-api.js -o datoka-api.mjs
curl --fail https://datoka-api.bhazarstudio.workers.dev/sdk/0.3.9/evidence.mjs -o evidence.mjs
curl --fail https://datoka-api.bhazarstudio.workers.dev/sdk/0.3.9/manifest.json -o sdk-manifest.json
node --input-type=module -e "import fs from 'node:fs'; import crypto from 'node:crypto'; const m=JSON.parse(fs.readFileSync('sdk-manifest.json')); for(const [remote,local] of [['datoka-api.js','datoka-api.mjs'],['evidence.mjs','evidence.mjs']]){const f=m.files.find(x=>x.path.endsWith('/'+remote));if(!f||crypto.createHash('sha256').update(fs.readFileSync(local)).digest('hex')!==f.sha256)process.exit(1);}"
node evidence.mjs verify evidence.json recipient-trusted-keys.json
```

The recipient supplies their own trusted issuer keys, separately from the evidence.
No Datoka account, wallet, payment or server access is needed for verification.
responseBodyStatus=not_included means only the signed declaration was checked.
With the response included, responseBodyStatus=matches confirms its hash matches.
A receipt attests a CLIENT DECLARATION. It does not prove provider origin, independent
observation, content truth, qualified time or blockchain anchoring of the response.
The same limitation applies even when payment settled successfully on Base.

## Smithery connection details (checked 2026-10-01)

Listing: https://smithery.ai/servers/bhazarstudio/datoka-api
The installed CLI 4.11.1 connection route returned 404. Use the documented REST
base https://api.smithery.ai/connect with your Smithery Bearer token.
Create a connection in a namespace you own using an unused connection ID:
PUT /<namespace>/<connectionId>
Body: {"server":"bhazarstudio/datoka-api","name":"Datoka API"}
Then GET /<namespace>/<connectionId>/.tools lists the tools.
POST /<namespace>/<connectionId>/.tools/get_api_public_keys with {} calls a free tool.
Tool arguments are the JSON body, without an arguments wrapper.
Inspect isError and structuredContent: HTTP 200 alone does not mean tool success.

The .tools REST method exposes arguments, not the MCP request metadata envelope.
An invalid, unsigned _meta probe was rejected as an unexpected argument. The
namespace MCP endpoint also returned 404 in our test. No paid settlement through
Smithery is claimed. Do not insert a wallet key in connection headers to work around
this. Discover and prepare via Smithery, then purchase directly using the saved
Datoka event and idempotency key. Do not restart an uncertain purchase on another route.

Official references:
https://smithery.ai/docs/api-reference/connect/call-tool
https://smithery.ai/docs/api-reference/connect/create-or-update-connection
https://github.com/x402-foundation/x402/blob/main/specs/transports-v2/mcp.md