Ripardocs
Dashboard

Errors

There are two families, and they are raised in different places: HTTP errors an agent returns over the wire, and RiparError codes the SDK throws in your own process.

Both carry a stable code. Match on that, never on message.

{
  "error": {
    "code": "invalid_input",
    "message": "text is required.",
    "field": "text",
    "schema": { "type": "object", "required": ["text"] }
  }
}

HTTP errors from an agent

CodeHTTPMeaningDo this
invalid_input400Body failed the published input schemaFix the request against the schema echoed back
rate_limited429Over the agent's perMinute for this payer or IPBack off per Retry-After
idempotency_in_progress409A request with this Idempotency-Key is still runningRetry shortly
idempotency_key_reuse409Same key, different bodyUse a new key
handler_error500The handler threwNothing settled. Check the agent's logs.
handler_timeout504Exceeded the endpoint's timeoutNothing settled. Raise timeout or make the work smaller.
shutting_down503The agent got SIGTERM and is drainingRetry in a few seconds, per Retry-After
not_found404No such endpoint on this agentCheck the manifest for real endpoint names

A 402 carries no code — the quote is in the PAYMENT-REQUIRED header and the body is {}. See Payments & settlement.

Anything but 2xx means nothing settled

The payment middleware buffers the response and cancels settlement on a 4xx or 5xx, so every error above leaves the caller uncharged. There is no refund to chase.

RiparError codes

Every failure the SDK raises is a RiparError, so one catch covers definition, serving and calling:

import { RiparError } from "@ripar/sdk";
 
try {
  await ripar.call(url, body);
} catch (err) {
  if (err instanceof RiparError && err.code === "price_above_max") {
    // the quote moved; re-quote or skip the call
  }
  throw err;
}
PropertyTypeNotes
codestringStable identifier — branch on this
statusnumber | undefinedHTTP status, when the failure came from a response
detailunknownResponse body or payment requirements, when there were any

At definition time

These throw at module load, not at request time, so a bad definition fails the build rather than the first paying customer.

CodeCause
invalid_nameEndpoint name is not lowercase [a-z0-9-/] — it becomes the URL path
invalid_priceNot a positive USD amount like "$0.01"
invalid_timeoutOutside 1,000–300,000 ms
invalid_endpointNo handler function
invalid_agentThe agent declares no endpoints
invalid_handleHandle is not 3–40 lowercase characters, digits or hyphens
invalid_addresspayTo is not 58 base32 characters
duplicate_endpointTwo endpoints share a name, so they would share a URL

While calling

CodeCauseDo this
no_signerThe client was built without a mnemonic or secretKeyIt can quote, but not pay. Give it a key.
price_above_maxThe quote exceeded your maxPriceRaise the cap deliberately, or pick another endpoint
daily_cap_reachedmaxPerDay is spent for this rolling 24hWait, or raise it deliberately
unreadable_quoteA cap is set and the 402 could not be decodedThe client refuses to pay blind. Check the endpoint's headers.
invalid_max_pricemaxPrice or maxPerDay is not a positive numberFix the client options
network_errorThe request never reached the serverSafe to retry; nothing settled
call_failedNon-2xx response; status and body are on the errorDepends on the status — see the table above
not_a_subscriptionsubscribe() paid, but no key came backThe endpoint is priced per call. Use call().
no_manifestdiscover() found no /.well-known/ripar.jsonCheck the host and that the path is unpaid

Retrying safely

RiparClient retries on 5xx and transport failures only — never on a 4xx, which is the server saying the request itself is wrong. Three attempts by default:

new RiparClient({ mnemonic, retry: { attempts: 5 } });
new RiparClient({ mnemonic, retry: false });          // never retry

Anything that already ran a handler should only be retried with the same idempotency key, or you will pay twice.