Skip to main content

Vault API

The Vault API handles all signing operations — EVM transactions, EIP-712 typed data, Solana transactions, and the approval/rejection flow.

Sign Transaction (EVM)

Sign and optionally broadcast an EVM transaction. The transaction is evaluated against the agent’s policies before signing.
Auth: Agent JWT Request Body:
Success Response (200):
Pending Approval Response (202):
Policy Denied Response (403):

Wallet Actions

Privy-style wallet-action routes expose quote/create/status flows over the existing vault and policy engine.

Quote EVM Transfer

Auth: Owner/admin browser session with recent MFA Quotes accept the same body as transfer creation:

Create EVM Transfer

Auth: Agent JWT with the required signer authorization for wallet actions Native and selector-gated ERC20 transfer actions return:
  • 200 with status signed or broadcast when policy allows signing.
  • 202 with status pending_approval when policy requires manual approval.
  • 403 with status rejected when policy denies the action.
  • 429 when policy rate limits reject the action.
  • 500 or 502 when signing or RPC submission fails; the error body includes data.actionId when an action row was created.
Broadcasting actions require idempotency. Set a stable referenceId for caller-side dedupe and transaction lookup. Signed-only artifacts do not consume spend because no on-chain submission has occurred. A transaction that reaches broadcast, confirmed, or outcome_unknown does consume spend: Steward durably records a stable accounting event identity and original occurrence time on the transaction, then completes spend and aggregation idempotently. If that accounting backend is temporarily unavailable after submission, the route returns retryable 503 with accounting_effects_pending; retry the same idempotency key or referenceId so Steward can finish accounting without resubmitting or moving the event into a later spend window. Monero transfers use the same durable aggregation protocol, but do not enter EVM-denominated USD spend until a vetted XMR valuation model is configured. ERC20 transfers require an enabled contract-allowlist policy for the token contract and transfer(address,uint256) selector (0xa9059cbb) with recipient allow/block constraints plus maxAmount. Approved ERC20 actions sign or broadcast against the token contract with zero native value, persist token/recipient/amount action metadata, and reject missing allowlists or over-limit amounts before signing. Settled token balance/spend accounting and confirmation polling remain follow-up work.

Create Send-Calls Intent

Auth: Agent JWT with the required signer authorization for wallet actions Send-calls creates a batch-call wallet-action intent. Today it resolves to status pending_approval or rejected; execution continues through the manual approval/intents workflow. Calldata-bearing calls are rejected unless selector-specific policy extraction or the explicit unsafe signing opt-in is configured.

Get Transfer Action Status

Auth: Agent JWT plus owner/admin browser session with recent MFA This status endpoint is transfer-only and returns status pending_approval, rejected, signed, broadcast, confirmed, failed, outcome_unknown, or retired. Send-calls status is available through transaction and intent history until a dedicated status route is added.

Retire a Signed Artifact

Auth: Owner/admin browser session with recent MFA Request body: { "reason": "operator explanation" }. This endpoint is intentionally narrower than the generic transaction lifecycle. A signed artifact remains independently broadcastable, so provider errors and local failures cannot relabel it as failed. At signing time Steward stores only immutable, digest-bound public evidence—never signed bytes. Solana evidence binds the deterministic signature, signer, message intent, and either the recent blockhash plus last-valid height or the durable-nonce account and authority. EVM evidence binds the exact transaction hash, recovered signer, nonce, and caller intent. Retirement first checks the exact artifact. A landed artifact is reconciled to its chain state. An absent recent-blockhash Solana artifact can retire only beyond its recorded last-valid height; an absent durable-nonce artifact only after the exact nonce account advances; and an absent EVM artifact only after the signer’s finalized nonce is greater than the recorded nonce. Live artifacts, malformed evidence, and any RPC uncertainty remain signed and continue to block deletion. The evidence digest is part of the retirement CAS and the state transition plus required audit commit atomically.

Sign Typed Data (EIP-712)

Sign structured data using eth_signTypedData_v4. Used for DEX approvals, ERC-20 permits, and other typed signatures.
Auth: Agent JWT Request Body:
Response:

Sign Solana Transaction

Sign a serialized Solana transaction and optionally broadcast it.
Auth: Agent JWT Request Body:
Response:

Sign Bitcoin PSBT

Sign a scoped Bitcoin PSBT for an agent wallet. The route signs matching wallet inputs only; it does not broadcast the transaction.
Auth: Agent JWT with signer authorization for sign_transaction, or tenant owner/admin session with recent MFA where configured. Request Body:
Success Response (200):
transactionId is Steward’s transaction record ID. When finalize is true and every input can be finalized, the response may also include finalizedTxHex, Bitcoin txId, vsize, and feeSats. Steward still does not broadcast that raw transaction; submit it through your own Bitcoin broadcaster or indexer integration. Before signing, Steward decodes standard destination outputs and evaluates the agent’s spend and address policies. It also enforces Bitcoin raw-signing-chain policy requirements and fee caps before returning a signed PSBT or finalized raw transaction metadata.

Safe retry guidance

Provide a stable referenceId for your business operation and an Idempotency-Key header when your deployment enforces or accepts idempotency on sensitive mutations. On network timeouts, retry the same PSBT with the same caller reference and idempotency key, then query transaction history by referenceId before creating a replacement request. If you requested finalize: true, treat a returned finalizedTxHex as a broadcast-ready artifact that may already have been handed to your own broadcasting layer. Do not blindly retry downstream broadcast attempts without checking your broadcaster or indexer for the Bitcoin txId; retrying a finalized raw transaction is different from retrying Steward PSBT signing.

Encrypted Private Key Import

Encrypted import lets a tenant owner/admin replace an agent wallet key without sending a top-level plaintext privateKey field. The import session is one-time, short-lived, stored as an encrypted auth-store record, and bound to the selected tenant, agent, and chain.
Auth: Tenant owner/admin browser session with recent MFA. API-key automation is rejected when the sensitive-action MFA policy is enabled. Feature flags: STEWARD_ALLOW_PRIVATE_KEY_IMPORT=true and STEWARD_ALLOW_VAULT_PRIVATE_KEY_IMPORT=true

Initialize

chain must be "evm" or "solana". The response returns the server X25519 public key, expiry, and AAD fields the client must bind into encryption:

Submit

Encrypt the raw private key client-side with X25519-HKDF-SHA256-AES-256-GCM. Use the returned importSessionId as the AES-GCM AAD. The HKDF info string is:
Submit only the encrypted envelope:
Wrong-agent submits return 400 and do not consume the original session. A later submit to the original agentId can still succeed. Once the tenant, agent, chain, envelope shape, and decrypted key validate, Steward atomically consumes the session before writing the new encrypted wallet. Replays after a successful submit return 400 with an invalid-or-expired session error. Session records are serialized through Steward’s KeyStore envelope and stored through the shared auth StoreBackend: Redis when configured, otherwise Postgres auth_kv_store when migrations are available, otherwise an in-memory local-development fallback. This is not an HSM-backed import-session store. Production deployments should configure Redis or run migrations so init and submit can land on different API replicas. Production startup fails before accepting traffic if any auth store falls back to memory, and /ready reports the complete mapping in checks.authStores. Only a guaranteed single-instance deployment may acknowledge restart-unsafe memory storage with STEWARD_ALLOW_MEMORY_AUTH_STORES=true. Plaintext privateKey fields, malformed envelopes, expired sessions, tenant or agent mismatches, and failed decryptions fail closed. Audit and webhook metadata are redacted and never include the plaintext key or ciphertext.
Success Response (200):

Approve Transaction

Manually approve a pending transaction from the approval queue.
Auth: Tenant API key (agents cannot approve their own transactions) Response:

Reject Transaction

Reject a pending transaction.
Auth: Tenant API key

Pending Approvals

List transactions awaiting manual approval.
Auth: Agent JWT or tenant key Response:

Transaction History

List all transactions for an agent.
Auth: Agent JWT or tenant key

List Transactions

Returns full transaction records for an agent with pagination and filters.
Auth: Agent JWT or tenant key Query Parameters:
referenceId filters transactions whose action payload contains either referenceId or reference_id. This matches transfer, send-calls, user-operation, EIP-7702 authorization, raw-signing, and Bitcoin PSBT signing actions that store caller-provided reference IDs.

Get Transaction

Returns one full transaction record by ID.
Auth: Agent JWT or tenant key

Get Addresses

List all wallet addresses across chain families.
Auth: Agent JWT or tenant key

Break-Glass Plaintext Key Import

Import an existing private key into the vault.
Auth: Tenant owner/admin browser session with recent MFA. Both STEWARD_ALLOW_PRIVATE_KEY_IMPORT=true and STEWARD_ALLOW_VAULT_PRIVATE_KEY_IMPORT=true must be enabled. Request Body:
Prefer the encrypted import session for hosted and browser-based flows. Plaintext import is a break-glass server-side route for controlled operator environments only. The imported key is immediately encrypted, the response is no-store, and the plaintext is never stored or logged.

RPC Passthrough

Proxy read-only RPC calls to the appropriate chain provider.
Auth: Agent JWT Request Body: