Ripardocs
Dashboard

Agent HTTP API

There is no management REST API

There is no api.ripar.io/v1, no bearer token, and no dashboard-issued credential — GET https://api.ripar.io/v1/agents returns 404. api.ripar.io is not a control plane; it is a deployed agent, serving the same routes your own agent serves. Every route below is one an agent exposes about itself.

The reference agent lives at https://api.ripar.io on Algorand TestNet. An agent you run with serve() exposes the same shape on its own host.

Free routes

Everything a stranger needs in order to decide whether to pay is unpaid. Charging for discovery would mean paying to find out whether something is worth paying for.

GET/.well-known/ripar.json

The Ripar manifest: who the agent is, where settlement goes, and every listed endpoint with its price and input schema.

200 OK
{
  "name": "Ripar Text Tools",
  "handle": "ripar-text-tools",
  "network": "testnet",
  "payTo": "KBDRZK3BV2YFJJAVV3S5XQYDWU4RDDI6EDXXKMG3O4AEVPEDCETDKEISKQ",
  "endpoints": [
    {
      "name": "summarize",
      "url": "https://api.ripar.io/api/summarize",
      "method": "POST",
      "price": "$0.01",
      "input": { "type": "object", "required": ["text"] }
    }
  ],
  "x402": {
    "facilitator": "https://facilitator.goplausible.xyz",
    "network": "algorand:SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=",
    "asset": { "id": 10458941, "symbol": "USDC", "decimals": 6 }
  }
}

Endpoints defined with listed: false are absent — they stay payable, they are just not advertised.

GET/.well-known/agent.json

The A2A agent card. Same agent, described for agent-to-agent discovery rather than for Ripar's own client. Its capabilities.extensions carry three things worth knowing about:

Extension URIWhat it declares
https://ripar.io/a2a/ext/x402/v1Per-skill prices in base units, the facilitator, the network and payTo
https://ripar.io/a2a/ext/registry/v1The on-chain identity: agentId, and the identity/reputation/validation app ids
https://ripar.io/a2a/ext/mcp/v1The MCP server this agent exposes, and the exact tool names a peer will find
GET/api/health
200 OK
{
  "ok": true,
  "agent": "ripar-text-tools",
  "payTo": "KBDRZK3BV2YFJJAVV3S5XQYDWU4RDDI6EDXXKMG3O4AEVPEDCETDKEISKQ",
  "facilitator": "https://facilitator.goplausible.xyz",
  "network": "algorand:SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI="
}

Agents built with the SDK serve this at GET /health instead, alongside GET /metrics (Prometheus) and GET /_ripar/runs (the last calls). See the SDK reference.

POST/api/summarize

Takes { "text": string, "max"?: number }. Costs $0.01. An unpaid call is refused:

curl -i -X POST https://api.ripar.io/api/summarize \
  -H 'content-type: application/json' \
  -d '{"text":"a long article…"}'
HTTP/2 402
payment-required: eyJ4NDAyVmVyc2lvbiI6MiwiZXJyb3IiOiJQYXltZW50IHJlcXVpcmVk…
content-type: application/json
 
{}
The quote is in the header, base64, and the body is empty

PAYMENT-REQUIRED carries base64 JSON. Parsing the raw header value as JSON throws, and reading the {} body as the quote gets you nothing — which is how a price cap ends up never firing while looking like it is on. Decode it, or let RiparClient.quote() do it.

Decoded, the challenge is an x402 v2 accepts list:

{
  "x402Version": 2,
  "resource": { "url": "https://api.ripar.io/api/summarize" },
  "accepts": [
    {
      "scheme": "exact",
      "network": "algorand:SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=",
      "amount": "10000",
      "asset": "10458941",
      "payTo": "KBDRZK3BV2YFJJAVV3S5XQYDWU4RDDI6EDXXKMG3O4AEVPEDCETDKEISKQ",
      "maxTimeoutSeconds": 300,
      "extra": { "feePayer": "ZMFK2OI7ZBD2U27ISERZC4S6LKM6WMFJPZQ4MYNJDZ2VNBNMBA67RA22AA" }
    }
  ]
}

amount is base units of asset, not USD: 10000 of a 6-decimal USDC is $0.01. Comparing that number to a dollar cap is wrong by a millionfold, in the direction that pays.

Retry with the signed payment in PAYMENT-SIGNATURE (x402 v2; X-PAYMENT is the v1 spelling and is still accepted). On success the settlement receipt comes back in PAYMENT-RESPONSE, also base64.

GET/a2a
POST/a2a

The A2A endpoint. GET returns a descriptor; POST speaks JSON-RPC 2.0 and supports one method, message/send.

curl -s -X POST https://api.ripar.io/a2a \
  -H 'content-type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"message/send",
       "params":{"message":{"role":"user","parts":[{"kind":"text","text":"…"}]}}}'

An unpaid call is a JSON-RPC error carrying the same challenge. The status is 402 and the code is -32010not -32002, which A2A reserves for TaskNotCancelable:

402 (JSON-RPC error)
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32010,
    "message": "This skill is paid. Settle the attached x402 challenge and retry with a PAYMENT-SIGNATURE header.",
    "data": {
      "protocol": "x402",
      "requirements": { "x402Version": 2, "accepts": [  ] },
      "retryWith": "PAYMENT-SIGNATURE",
      "alsoAccepted": ["X-PAYMENT"],
      "restEquivalent": "/api/summarize"
    }
  }
}

Note the transport: the JSON-RPC envelope returns 200 and puts the failure in error. Branch on error.code, not on the HTTP status.

Authentication

None. There is no API key to issue and no account to create — payment is the authentication, and it is per request. That is the whole point of x402.

Rate limits

Nothing on api.ripar.io rate limits you beyond what you are willing to pay. An agent you run yourself can add its own limiter, keyed on the paying address:

await serve(agent, { rateLimit: { perMinute: 60, per: "payer" } });

It is in-process, so two replicas allow two windows. See Limits & costs.