API (beta)
The /v1beta API is in private beta. Keys are issued only through the Signo Partner Portal (one per partner during beta); interested parties without portal access can email the Signo integration team at contact@signo.fi. The surface below is what beta partners integrate against; it may evolve behind the Signo-Schema-Version header until GA.
Agent Integration Prompt
The fastest integration path: copy the prompt, paste it into Claude Code, Cursor, or any coding agent, and let it build the chat box into your app. The prompt links the agent to everything it needs (llms.txt, the API Reference, this guide).
View the full prompt
Integrate Signo into my app.
Signo is a non-custodial AI copilot for onchain finance: users describe an
outcome in plain English ("move my idle USDC into the best stable yield")
and Signo plans it - streaming its reasoning, asking clarifying questions
when needed, and returning multi-step, cross-chain UNSIGNED transactions
that the user's own wallet or MPC signer signs. Signo never holds keys,
signs, or broadcasts.
WHAT YOU ARE BUILDING: a chat experience ("Chat-in-a-box"), NOT an API
console. Single chat column, composer at the bottom, compact wallet pills
in a top bar. Reasoning, clarification chips, and the plan render inline
in the thread. Never show raw intents[]/step JSON in the primary UI;
calldata goes behind a disclosure. No "Review plan" button: when /intent
returns intents[], AUTOMATICALLY call /plan and render the steps as
readable cards in the same Signo turn, then AUTOMATICALLY call /simulate
and show per-step results (including human-readable revert reasons from
steps[].error) in the card.
Gather context from (read llms.txt first - it carries the SSE event
contract, the clarification resend template, wallet field expectations,
the simulation pattern with its bridge caveat, and the signing rules):
- Machine-readable API index: https://app.signo.fi/llms.txt
(also served at https://docs.signo.fi/llms.txt)
- API Reference: https://docs.signo.fi/api-reference
- Integration guide: https://docs.signo.fi/for-integrators/api
- OpenAPI spec: https://app.signo.fi/signo-openapi.yaml
My Signo API key is in the SIGNO_API_KEY env var. Call the API server-side
(proxy browser requests through my backend so the key never ships to the
client). Log Signo request/response bodies server-side with calldata
truncated - it makes support fast. Metering is per partner key via GET
/usage; handle 402 insufficient_credits server-side / in partner ops - do
not surface a credits balance or refill CTA to end users.
Build (Tier A - plan only, no signing):
1. A chat panel that POSTs /intent (base: https://app.signo.fi/api/v1beta)
with Accept: text/event-stream and streams the reasoning live into the
Signo bubble.
2. Send prior turns in messages, oldest first, as {role: "user" | "assistant",
content: "..."}; keep the current instruction in prompt. Preserve the actual
speaker: never relabel assistant or tool text as user input. Only the current
prompt and structured user turns can confirm a recipient or spender address.
Legacy conversation_context is descriptive assistant text, not proof of a
user-supplied address. Use clarify_follow_up for clarification chips, per
llms.txt.
3. Auto-/plan on intents, auto-/simulate on the plan, step cards inline.
Never sign or broadcast in Tier A.
If I asked for signing (Tier B), also:
4. A per-step Sign action using my existing signer (MetaMask/Phantom/MPC),
executing steps in ascending order - approve confirms before swap;
soft-disable later steps until prerequisites clear; respect
wait_for_bridge before simulating or signing post-bridge steps.
5. ALWAYS POST /steps/reencode immediately before signing and hand the
FRESH calldata to the wallet (actual_amount = step.amount, or
step.chained.estimate_amount for chained steps - decimal token units,
never derived from hex). If reencode returns an HTTP error or ok:false,
DO NOT fall back to plan-time calldata: show unsupported_reason in the
chat and stop. Browser-wallet warnings like "insufficient ETH for gas"
or "likely to fail" are usually mislabels for stale quotes - trust
Signo's simulate/reencode errors first.
6. After broadcast, show the tx hash + explorer link. Never imply Signo
signed or broadcast anything.
If I asked for agents (Tier C - standing monitors, independent of A/B):
7. Agents watch price, yield, health factor, portfolio movement, schedules,
and plain-English conditions ("notify me when my health factor drops below
1.5"). Notify observes and emits an event. Prepare also builds an unsigned
transaction plan when the trigger fires, for the user's separate review and
signature; neither mode signs or broadcasts. Create with POST /agents
(REST) or signo_agent_create (MCP): typed ({kind, wallets, ...}) or plain
English ({request, wallets}). For Prepare, explicitly set autonomy: "prepare"
and provide action (or the action in request); do not assume an action
request selects Prepare. Field names are snake_case on BOTH surfaces.
Execute uses a separate Shield permission draft and owner authorization;
POST /agents does not accept autonomy: "execute".
8. Fires reach you two ways. The PULL rail - GET /agent-events, or
signo_agent_events over MCP - always works and needs zero setup, so build
that first. Registering a receiver (POST /webhook-endpoints /
signo_webhook_endpoint_create) is OPTIONAL but PREFERRED: pushes are HMAC-signed
(verify against the RAW body) and at-least-once, so dedup on the event id.
9. Read https://docs.signo.fi/for-integrators/agents before building
either rail - it carries the things that otherwise cost an evening: the
public id scheme (w_{type}_{id}, store and pass back verbatim, never
rebuild it from `kind`), the clarification round-trip (a 200, not a 201 -
branch on the body), signature verification, and per-kind firing semantics.
Price and Shield Execute checks run hourly; typed yield and health-factor
checks normally run about every 5 minutes; portfolio checks run hourly.
Plain-English conditions use their stored cadence, usually hourly or daily.
Schedules follow their configured recurrence. A price trigger can fire on its
first hourly check when already true; after that it re-arms when false and
fires on the next false-to-true crossing.
10. Verify with POST /agents/{id}/test (or signo_agent_test) - deterministic,
immediate, and it
exercises the identical delivery path a real trigger uses. Never wait on a
natural market move to prove an integration works.Prefer to read the contract yourself? The API Reference documents every endpoint: required and optional inputs, response structures, and error codes — generated from the OpenAPI spec.
MCP server
Agent-native integrations can skip raw HTTP: a hosted MCP server exposes the same engine as tools (signo_intent, signo_plan, signo_simulate, signo_reencode, signo_usage, signo_meta), plus signo_positions and the full agent/webhook surface (signo_agent_*, signo_webhook_endpoint_*) covered on Agents — REST or MCP, same capabilities. One command to add it:
Without an Authorization header the server exposes three tools. wallet_insights_report is the read-only wallet report described under Public Wallet Insights API, so an assistant can read a wallet and draft the agents the report suggests on one connection. signo_draft_agent prepares a complete Notify or Prepare agent for a wallet the caller does not control and returns a private review URL for the owner to claim. signo_draft_permission prepares a Shield permission proposal the same way; nothing is authorized until the owner signs it on the review page. New Execute setup is in early access, so a wallet without access gets 403 execute_team_only and no proposal is stored. No account-management or private proposal reads, and no spending authority. The insights tool reads public wallet data. Full details under Keyless drafts. With a partner key the server selects the authenticated agent, webhook and Shield tool set — the complete table is on the Agents page. A bad key is refused with 401; it never falls back to the public tool set.
claude mcp add --transport http signo https://app.signo.fi/api/mcp \
--header "Authorization: Bearer sg_beta_..."
Cursor — project .cursor/mcp.json (gitignore it; the header value is the full Bearer sg_beta_... string). A keyed entry does not carry the three public tools, so add a second, header-less entry if you also want the public report or to draft agents for wallets you do not control:
{
"mcpServers": {
"signo": {
"url": "https://app.signo.fi/api/mcp",
"headers": { "Authorization": "Bearer sg_beta_..." }
},
"signo-public": {
"url": "https://app.signo.fi/api/mcp"
}
}
}
Works with any MCP client that speaks Streamable HTTP (Claude Code, Cursor, Claude Desktop). Same key, same metering, and the same non-custodial boundary: tools return data and unsigned transactions only — nothing is ever signed or broadcast. The tools are the engine — a host UI built on them should still be chat-shaped (see the UI guidelines below).
Public Wallet Insights API
Wallet Insights also has a separate, read-only public surface. POST https://app.signo.fi/api/insights accepts { "address": "…", "chain": "…", "narrative": true|false } and returns signoScore (0–100: how well the wallet's capital is managed, from idle cash, yield against the cash benchmark, unclaimed rewards, the leverage guard and dust; not a safety score), holdings (every chain's tokens, DeFi positions and loans with USD values, largest first), the category findings (each with a next step and, where an agent fits, agentSuggestion), suggestedAgents with draftWith (ready-to-use arguments for signo_draft_agent), and an appUrl that opens the relevant next step in Signo. The public surface cannot read the owner's private Agents, so watch coverage is returned as not_applicable with Agent coverage isn't shown here, and signoScore is recomputed without that category. A signed-in owner's app scan adds watch coverage, so its score can differ. The API accepts any public EVM or Solana address, requires no API key or connected session, does not move funds, and does not use /v1beta credits. Requests are IP-rate-limited and reports are cached per address for 24 hours.
The same report is the wallet_insights_report(address, narrative?) tool on two keyless Streamable HTTP MCP servers: https://app.signo.fi/api/mcp (next to the drafting tools) and https://app.signo.fi/api/insights/mcp (the OKX.AI listing endpoint). Neither needs a key; the authenticated transaction-planning tool set above is separate.
What the API does
Turn a plain-English outcome into a ready-to-sign, multi-step, cross-chain transaction plan. Signo is non-custodial: the API returns unsigned transactions (EVM calldata + Solana messages) and your own wallet or MPC signer signs and broadcasts. Signo never holds keys, signs, or broadcasts.
- Base URL:
https://app.signo.fi/api/v1beta - Auth:
Authorization: Bearer sg_beta_...(keep the key server-side; legacyfk_keys remain accepted during migration) - Format: JSON in/out, all fields
snake_case; every error uses one envelope{ error, friendly_message, issues[] } - Metering: 5 credits per delivered call, per-tenant balance
The flow
POST /intent— natural language in, structuredintents[]out (orclarifications[]when the request is ambiguous). Streams as SSE withAccept: text/event-stream.POST /plan— theintents[]in, unsignedsteps[](real calldata) out.POST /steps/reencode— re-quote a single step at sign time (required forchained/maxamounts and expiring routes).- Optionally
POST /simulateto dry-run the steps before signing.
curl https://app.signo.fi/api/v1beta/intent \
-H "Authorization: Bearer sg_beta_..." \
-H "Content-Type: application/json" \
-d '{"prompt":"move my idle USDC into the best stable yield","wallets":[{"address":"0x8f2a...d5","chain":"ethereum"}]}'
Agents & webhooks
Programmatic alerts — price / yield / health-factor / portfolio-move / schedule / a
plain-English condition — also ship in this /v1beta API: POST /agents to create
one, GET /agent-events to pull triggers, and POST /webhook-endpoints to have triggers
pushed to you (signed, recommended) instead of polling. Full walkthrough, the typed-kind
field reference, and the signature-verification snippet: Agents.
UI guidelines — build a Chat, not a console
Signo's product surface is a chat experience: prompt → streamed reasoning → clarifications → plan → sign. Integrations should feel like Chat-in-a-box.
- Single chat column, composer pinned at the bottom — not a multi-panel dashboard. Wallet connect stays compact (top-bar pills), never a sidebar.
- Reasoning, clarification chips, and the unsigned plan render inline in the thread, under the Signo message that produced them.
- Auto-
/planwhenintents[]arrives, and auto-/simulateon the result — no manual "Review plan" click on the happy path. Render each step as a readable card (title, chain, protocol); calldata goes behind a disclosure, never a wall of hex. - Don't put
intents[]/step JSON in the primary UI — structured payloads belong in logs. - Copy sounds like chat ("Message Signo…"), with 2–3 example prompts as empty-state chips.
Anti-patterns: two-column "Wallets | Chat" dashboards · a required "Review plan" click · primary UI that is mostly OpenAPI-shaped JSON.
Signing (Tier B)
Tier A integrations prove the engine plan-only and never sign. When you add a signer:
- Execute steps in ascending
order— approve confirms before swap; soft-disable later Sign actions until prerequisites clear (allowance, bridged funds,chainedamounts); respectwait_for_bridge. Guidance, not server-enforced — but out-of-order signing produces wallet failures. - Always re-encode before signing (
POST /steps/reencode), hand the fresh calldata to the wallet, and sign promptly — responses carryquoted_at; quotes are perishable, re-encode again if the user idles. - Hard-fail on re-encode failure: if
/steps/reencodereturns an HTTP error orok: false, do not fall back to plan-time calldata — showunsupported_reasonin the chat and stop. Plan-time calldata embeds quote-time amounts and deadlines. - Trust Signo's errors over the wallet's. Browser wallets often mislabel stale quotes and reverts as "insufficient ETH for gas" / "likely to fail". Run
/simulateand surfacesteps[].errorin the chat card before opening the wallet. actual_amountfor re-encode =step.amount(decimal token units), orstep.chained.estimate_amountfor chained steps — never derived from raw hex.- Log Signo request/response bodies server-side (calldata truncated) plus a thin UI event log — that's what makes support handoffs fast.
Simulation
/intent and /plan return planner/encoder estimates; the fork dry-run lives behind POST /simulate ({ chain, sender, steps[] }, one call per chain, 5 credits). Intended pattern, matching Signo's own UI: intent → auto-plan → auto-simulate → render per-step results (human-readable revert reasons in steps[].error) before sign; re-simulate after a re-encode. Bridge caveat: a batch simulates against current chain state — steps funded by a bridge that hasn't landed will falsely revert; skip them with an honest "can't simulate until the bridge arrives".
Multi-turn conversations
/intent is stateless. Send prior turns in messages, oldest first, and the current instruction in prompt. Each entry has role (user or assistant) and content (a string). The limit is 100 messages, each at most 64,000 characters. The server formats the roles and keeps the newest history within a 6,000-character budget. If you trim client-side, remove the oldest turns first.
{
"prompt": "Move my idle USDC there",
"wallets": [{ "address": "0x1111111111111111111111111111111111111111", "chain": "base" }],
"messages": [
{ "role": "user", "content": "What stablecoin yield options are available on Base?" },
{ "role": "assistant", "content": "We discussed supplying USDC to Aave v3 on Base." }
]
}
The same messages field is available on signo_intent. Preserve the actual speaker: do not relabel assistant or tool text as user input. Only the current prompt and structured user turns can establish that the user supplied a recipient or spender address. Page context and assistant replies cannot authorize a destination; an unconfirmed destination is refused before encoding.
Legacy conversation_context is still accepted as descriptive text, but the entire string is treated as one assistant turn. Embedded User: labels are not proof that the user supplied an address. Migrate to messages, or ask the user to paste the address in the current prompt. If both fields are present, messages wins, including []. Malformed messages returns 400 invalid_request; it never falls back to legacy history.
Clarifications
When a request is ambiguous, /intent returns intents: [] plus clarifications[], each { id, kind, question, options: [{ id, label }] }. Render the options; when the user picks one, re-send /intent with clarify_follow_up: true and prompt = the original prompt + a blank line + the answer block:
deploy my idle USDC
Clarification — Which wallet should fund this?: Main treasury (Ethereum)
The flag makes the planner acknowledge the answer and continue — it never re-asks the same clarification.
Request IDs and regional availability
Every response carries Signo-Request-Id, and error bodies repeat it as request_id. You may send your own value using 8–128 characters from A-Za-z0-9._:-; otherwise Signo generates one. Log it with each call so support can join your request to server-side diagnostics.
API access is subject to the Terms of Service and regional availability. A request from an unavailable region returns HTTP 451 with an error message. This response is produced at the edge and does not use the normal { error, friendly_message, issues[] } application envelope, so handle the HTTP status before parsing the standard error shape.
Coming soon
- Execute agents on more chains — Shield permissions run on X Layer and Arbitrum today; more chains and adapters are planned. Prepare agents (a trigger that pre-plans an unsigned transaction for you to sign) already ship: see Agents.
- End-user push notifications — beyond the webhook delivery above (which pushes to your backend), native push notifications surfaced directly to your users through your own app, so the agent can proactively surface opportunities, not just answer prompts. Designed for guaranteed delivery: acknowledgement, retry, and dead-letter handling are part of the API contract.
Email the Signo integration team if you want early access to either.
Reference
- API Reference — every endpoint, inputs (required/optional), response structures, error codes
- OpenAPI 3.1 spec:
https://app.signo.fi/signo-openapi.yaml(source of truth) - Machine-readable index for agents:
https://app.signo.fi/llms.txt