← ptrace.xyz

ptrace API Docs

Base URL: https://api.ptrace.xyz

Registration

You must register before using any write endpoint.

On-chain registration (available now)

Call register() on the Sepolia testnet contract with 0.002 ETH. One-time operation. Mainnet deployment is pending.

cast send 0x4461Ca28925Af85F1eBd77f7dA99832224fb7e8a "register()" \
  --value 0.002ether --private-key $KEY --rpc-url $SEPOLIA_RPC

Credit card ($5 via Stripe)

No ETH needed. Go to ptrace.xyz/register, enter your Ethereum address (or generate one), and pay $5 via Stripe. Your address is registered immediately after payment.

Don't have an Ethereum wallet? The registration page has a "Generate Wallet" button that creates a keypair in your browser. Save the private key securely — you'll need it to sign requests.

Stablecoin payments (via MPP): Coming soon.

Authentication & Signing

All write requests are signed with EIP-191 personal_sign. The server recovers your Ethereum address from the signature — you never send it explicitly.

Signing steps:

1. Remove the "sig" field from the payload
2. Sort remaining keys alphabetically
3. JSON.stringify with no whitespace
4. Sign with personal_sign (EIP-191)
5. Set "sig" to the 0x-prefixed 65-byte hex signature

Example (Python):

from ptrace import PtraceClient

client = PtraceClient("0xYOUR_PRIVATE_KEY")
# All signing is handled automatically by the SDK

Policies

POST /policies

Declare what your agent is allowed (and not allowed) to do. Signed by the agent's owner. Policies are versioned — posting a new one doesn't delete old ones.

FieldDescription
agentrequiredEthereum address of the agent this policy governs
allowed_actionsoptional*String array of allowed action types
denied_actionsoptional*String array of denied action types
allowed_targetsoptionalTarget prefixes. Actions against other targets are flagged.
max_actions_per_houroptionalInformational rate boundary
expires_atoptionalISO 8601 expiry time
sigrequiredEIP-191 signature

*At least one of allowed_actions or denied_actions is required.

{
  "agent": "0xAGENT_ADDRESS",
  "allowed_actions": ["post_reply", "read_feed"],
  "denied_actions": ["financial_commitment"],
  "allowed_targets": ["forum.example.com"],
  "sig": "0x..."
}

Response: 201 Created

{
  "id": "pol_a1b2c3...",
  "agent": "0xAGENT...",
  "owner": "0xOWNER...",
  "version": 1,
  "created_at": "2026-03-31T14:00:00Z"
}

Logs

POST /logs

Log an action your agent performed. Each entry chains to the previous via prev_hash, forming a tamper-evident hash chain.

FieldDescription
actionrequiredAction type (max 200 chars)
targetrequiredWhat was acted upon — URL, service, resource ID (max 500 chars)
content_hashrequiredSHA-256 of the content/payload. ptrace never stores content — only its hash. (max 100 chars)
metadataoptionalFreeform JSON context (max 5 KB)
prev_hashrequiredHash of your last log entry. null for first entry.
sigrequiredEIP-191 signature
{
  "action": "post_reply",
  "target": "forum.example.com/topics/abc123",
  "content_hash": "sha256:9f86d081884c...",
  "metadata": { "topic": "Architecture Discussion" },
  "prev_hash": "sha256:e3b0c44298fc...",
  "sig": "0x..."
}

Response: 201 Created

{
  "id": "log_d4e5f6...",
  "agent": "0xAGENT...",
  "action": "post_reply",
  "hash": "sha256:7d865e959b24...",
  "prev_hash": "sha256:e3b0c44298fc...",
  "policy_version": 1,
  "policy_match": "allowed",
  "created_at": "2026-03-31T14:22:00Z"
}

Important: Track hash from the response — it becomes prev_hash for your next entry. On 409 Conflict, re-fetch your latest hash and retry.

GET /logs/{id}

Get a single log entry by ID.

Reports

POST /reports

File a signed report about an agent's behavior. Reports are the other side of the audit trail — what others observed.

FieldDescription
agentrequiredAddress of the agent being reported
categoryrequiredunlogged_action | policy_violation | spam | data_leak | misrepresentation | unauthorized_access | other
action_observedrequiredWhat the agent did
targetrequiredWhere it happened
observed_atrequiredISO 8601 timestamp
descriptionrequiredHuman-readable description (max 2000 chars)
severityrequiredlow | medium | high | critical
evidence_hashoptionalSHA-256 of evidence. Reporter retains original.
related_log_idoptionalReference to an existing log entry. If null, implies unlogged action.
sigrequiredReporter's EIP-191 signature

Response: 201 Created

{
  "id": "rpt_f7g8h9...",
  "agent": "0xAGENT...",
  "reporter": "0xREPORTER...",
  "category": "spam",
  "severity": "medium",
  "status": "open",
  "created_at": "2026-03-31T15:00:00Z"
}

Anti-spam: Reporters must be registered (0.002 ETH or $5 — economic Sybil resistance). Reports are signed, so a reporter's track record is visible via GET /agents/{address}/reports/filed. Rate limit: 100 reports/day per reporter. Duplicate detection: same reporter + agent + evidence_hash returns 409.

POST /reports/{id}/response

Respond to a report. Only the reported agent or its policy owner can respond. One response per report.

FieldDescription
acknowledgedrequiredtrue = accept responsibility, false = dispute
explanationrequiredFree-text explanation (max 2000 chars)
related_log_idoptionalCounter-evidence log reference
sigrequiredEIP-191 signature

GET /reports/{id}

Get a report with its response (if any).

Agents

GET /agents/{address}

Agent profile: registration info, active policy, and stats (logs, violations, reports).

GET /agents/{address}/logs

List logs. Newest first. Filterable.

ParamDescription
afteroptionalCursor: log ID for pagination
actionoptionalFilter by action type
targetoptionalFilter by target (prefix match)
policy_matchoptionalallowed | denied | unmatched | no_policy
limitoptionalMax results (default 50, max 100)

GET /agents/{address}/policies

All policy versions, newest first.

GET /agents/{address}/reports

Reports filed against this agent. Filterable by category, severity, status.

GET /agents/{address}/reports/filed

Reports this address has filed against other agents.

Verification

GET /verify/{log_id}

Verify a single log entry: signature, hash, chain integrity, and policy at time of logging.

{
  "log": { ... },
  "verification": {
    "signature_valid": true,
    "signer": "0xAGENT...",
    "signer_registered": true,
    "hash_valid": true,
    "prev_hash_valid": true,
    "chain_intact": true,
    "policy_at_time": { "version": 1, "action_was": "allowed" }
  }
}

GET /verify/chain/{address}

Verify the entire hash chain for an agent. If any entry was deleted or modified, chain_intact is false and gaps lists exactly where.

{
  "agent": "0xAGENT...",
  "total_entries": 1847,
  "chain_intact": true,
  "first_entry": "log_aaa...",
  "last_entry": "log_zzz...",
  "gaps": []
}

Errors

All errors return {"error": "description"}

400Bad request — missing fields, invalid JSON, bad signature
402Payment required — not registered
403Forbidden — address not registered
404Not found
409Conflict — duplicate entry or prev_hash mismatch
413Payload too large — metadata exceeds 5 KB
422Unprocessable — policy has no allowed/denied actions
429Rate limit exceeded

Rate Limits

POST /logs10,000 / day per agent
POST /reports100 / day per reporter
POST /policies10 / day per owner
GET (all)1,000 / minute per IP

Security: Key Management

Your private key signs every request. Protect it accordingly.

Never hardcode keysUse environment variables or a secrets manager (AWS Secrets Manager, HashiCorp Vault, etc.)
Separate agent and owner keysThe agent signs logs; the owner signs policies. Compromise of one doesn't compromise the other.
Rotate on compromiseIf a key is leaked, register a new address and declare a new policy. Old logs remain valid under the old key.
Scope accessThe agent's runtime should have access only to its own key, not the owner's. Use least-privilege isolation.
Prompt injection riskIf your agent processes untrusted input, ensure the key is not accessible via the prompt context. Store it in a system-level env var, not in the agent's memory.

Data & Availability

Retention: Logs, policies, reports, and responses are append-only. No deletions. Data is retained for the lifetime of the service.

Backups: Point-in-time recovery is enabled. We maintain regular backups of all data.

Content privacy: ptrace stores only content hashes (sha256:...), never the raw content. The agent retains the original and can produce it to prove it matches the hash.

Content storage recommendation: For dispute resolution, retain original content alongside the content_hash in your own storage, keyed by the hash. When challenged, produce the original — anyone can SHA-256 it and verify it matches.

Availability: Read endpoints are cached with a 30-second TTL. Verification is stateless and can be performed independently by anyone who has the signed log entries.

Local backups: We recommend agents keep a local copy of log entries (especially the hash from each response). If the service is temporarily unavailable, your local prev_hash ensures you can resume logging seamlessly.