Skip to main content
The relayer API is how a wallet app, a bot or an agent talks to ProofBridge: it lists chains and routes, records ads and trades, hands back the transaction data each wallet signs, and collects the co-signatures that settle a trade. The rules on this page hold for every endpoint in the reference.

Base URL

The base URL depends on the environment:
Mainnet isn’t live yet. Use Soak to try ProofBridge today.
Every endpoint lives under /v1/, for example GET https://api-staging.pfbridge.xyz/v1/routes. The only routes outside /v1/ are the health routes. /v1 is part of each path; there is no separate version header. The relayer also serves its generated OpenAPI pages: the Swagger UI at /docs and the JSON document at /openapi.json. Some response types there are loose. Where they differ from this reference, this reference is right. CORS allows only the official app’s origin, so a page served from any other origin is refused by the browser. Server-side clients are not affected. Request bodies are JSON, up to 5 MiB. A larger body gets 413; a body that is not valid JSON gets 400.

Auth header

Send the access token on every route marked user:
You get tokens by signing a challenge with your wallet; see Authentication. There are two token types: A guarded route refuses a bad token before it does anything else: On a 401, refresh once and retry. If the refresh is refused too, sign in again.

Errors

Every error has the same envelope:
  • error is a machine code, present on coded refusals such as refresh-reused, claim-in-flight or route-retired. When it is there, branch on it. Some codes add extra keys (a claimId, a limit); each endpoint page lists them.
  • field and issues appear only on a validation 400. field is a dotted path, for example auth.sig or attachments.0.sha256.
  • Unknown keys are refused. A body or query with a key the endpoint does not take answers 400 property <key> should not exist.
  • Path ids. A path id that should be a UUID and is not answers 400 Validation failed (uuid is expected).
  • 5xx. A 503 keeps its message (it usually means “retry”). Any other 5xx answers Internal server error; show a generic “try again” message.

Rate limits

Limits are counted per route, in a 60-second window. Ten calls to one route do not use up another route’s allowance. Over the limit you get 429 with the message ThrottlerException: Too Many Requests, and the key stays blocked for one full window. The relayer does not expose Retry-After or X-RateLimit-* to browser code, so back off for 60 seconds instead of reading a header.

Pagination

Paged lists use a cursor. Pass the previous answer’s nextCursor as the cursor query parameter; nextCursor: null means you have the last page.
  • limit is 1 to 100, default 25 (notifications default to 20).
  • Most lists answer { data, nextCursor }. Notifications answer { items, nextCursor }. Read the key each endpoint page names.
  • The cursor is a row id. Lists ordered by id are not in creation order, so sort them yourself before showing them as “newest first”.
  • Some lists come back whole, unpaged: GET /v1/pods and GET /v1/accounts.

Value formats

Polling or the socket

The relayer pushes two kinds of event over one socket.io connection, on the namespace /notifications at the base URL:
The server disconnects the socket when the access token expires (reason io server disconnect) and socket.io does not reconnect on its own after that. Refresh the token and call connect() again. The socket is a hint, not the record: after a reconnect, re-read your screen’s data over HTTP. Notifications has the event list. Everything else you poll. The relayer watches the chains on its own loop, so polling it faster than these intervals gains nothing: All of these together stay well under the default 120 calls a minute.

Health routes

These three routes sit outside /v1/, need no auth and are not rate limited. They are for status pages and load balancers; a wallet app does not need them.

GET /

GET /health

Answers 200 while the database answers, and 503 with the same body when it does not. A dead Redis or a stale background loop only sets status to degraded; the call still answers 200.
A loop is stale when its last successful run is older than three times its own interval.

GET /readyz

On an instance that builds proofs, ready is true only when at least one chain is tracked and every chain’s local copy of the Merkle Mountain Range has caught up with the chain’s finalized head. The status is 200 when ready and 503 otherwise; the body is returned either way.
An instance that does not build proofs answers whether its database and Redis are up instead, with chains: [] and a checks object (db, redis).

Endpoint groups

Authentication

Sign in with SIWE or SEP-10, refresh, log out and link a second wallet.

Chains and routes

The chains, tokens and trade routes the relayer serves, with each route’s clocks.

Ads

Create, fund, withdraw from, update and close liquidity ads.

Trades

Reserve liquidity, get the order and lock data, and confirm deposits.

Settlement

Upload co-signatures and follow a trade to settlement.

Keys

Register, retire and revoke settlement keys.

Cancels

The self-serve endings for a trade that did not settle.

Disputes

Evidence uploads and the dispute case file.

Accounts

Your wallets and linked smart accounts.

Pods

Request and manage a hosted maker pod.

Notifications

The notification list, the unread count and the socket.

Faucet

Test tokens on test networks.

Stats

Network numbers, anchor freshness and an account’s track record.

Feedback

Send a report and attach files.