Skip to main content

Permits

A permit is the user’s approval for your app. It reads and signs for the wallets the user picked and for paper money, for 30 days.
  • Treat it like an access token. It acts for one user, within the wallets they picked, until it expires or is revoked. Store it on your server or in secure storage on the device, and never log it.
  • Connect again before expiresAt. Agents your app started then move to the new permit and keep running.
  • Disconnect with POST /partner/disconnect. The permit is revoked, and agents your app started stop trading. Users can also disconnect your app in Connected apps on Circuit.

Connecting

Your app never handles a passkey.
  1. POST /partner/connections with your app id, an X25519 public key and an optional returnUrl. The returnUrl must start with a URL registered for your app; app schemes such as yourapp://connected work.
  2. Open the url it returns in a real browser. On iOS use ASWebAuthenticationSession; on Android use a Custom Tab. Never use an embedded web view.
  3. Poll GET /partner/connections/{id} every retryAfterMs until sealedPermit arrives. It stays available until expiresAt, five minutes after you started.
sealedPermit is base64url of a 32-byte ephemeral X25519 public key, a 12-byte IV, then AES-256-GCM ciphertext. The key is SHA-256 of circuit-permit-handoff:v1 ‖ X25519(your secret, ephemeral) ‖ ephemeral ‖ your public key. The reference client does this for you.

Conversations

  • A conversation is a UUID your app picks. Send its next message with the same id to continue it.
  • A message id is a UUID your app picks per message. Reuse it when you retry; a retry never acts twice.
  • Polling: read the conversation again after retryAfterMs. When it is null, nothing is in progress.
  • Replies are Markdown: CommonMark with GFM tables. Render them with any standard renderer.

Actions and controls

Ask proposes trades, transactions and agent changes as actions.
  • Act only on what’s listed. An action’s decisions and an agent’s controls list exactly what your app may send now. Offer them however your interface likes.
  • state is for display. Use it to style what you show, and message for the detail. New states can appear.

Ids and amounts

  • Ids show their type: wal_ wallets, hld_ holdings, agt_ agents, op_ trades and transactions, aga_ agent changes, conn_ connections. Every row has one, and it never changes. Don’t parse them.
  • Amounts are decimal strings. A holding’s amount is negative for a short or a debt, and its symbol is the asset alone (BTC). USD values are decimal strings, or null when Circuit can’t price a holding.

Errors

A failed call answers its HTTP status and { "error": "<message for the user>" }. Every response carries x-circuit-request-id. Include it when you report a problem.

Versions

Every call sends Circuit-Partner-Version. The current version is 0.1.
  • Circuit serves one version at a time. A call that sends another version gets a 400 naming the version Circuit serves.
  • Within a version, changes only add. New fields, states, decisions and controls can appear; ignore the ones you don’t know.
  • A change your app could notice ships as a new version. Circuit tells every registered app before it does.
  • While the version starts with 0, the API is a preview. From 1.0, a version stays stable.
The whole contract is an OpenAPI 3.1 document at https://api.circuit.org/partner/openapi.json; each environment serves its own. Use it to generate a client in any language.

Changelog

0.1: the first version: connecting, account, conversations, actions, agent controls and disconnect.