Chainvara
Developers

Build on Chainvara in an afternoon

One REST API for wallets, transfers, payouts, tokens and compliance. Every call goes through the same policies, approvals and screening as the console, and every change reaches you as a signed webhook.

$ curl -X POST /api/v1/transfers …

201 transfer_8f2… pending_approval

webhook transfer.approved FOS-Signature ✓

webhook transfer.submitted 0x7a1…e04

webhook transfer.confirmed 12 confirmations

→ order #1042 marked paid

Quick start

1

Create a key

Sign up, open Developers and create a test key (fos_test_…). Test keys run on public test networks; live keys (fos_live_…) on mainnets.

2

Call the API

Send the key as a Bearer token. Add an Idempotency-Key to every POST so a retry never pays twice.

3

Listen

Register an https endpoint for webhooks, verify each signature, and react to transfer.confirmed.

curl https://www.chainvara.com/api/v1/transfers \
  -H "Authorization: Bearer $CHAINVARA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: order-1042" \
  -d '{ "wallet_id": "…", "asset": "USDC", "amount": "250", "destination": "0x…" }'

REST API

Base URL

https://www.chainvara.com/api/v1, JSON in and out.

Scoped keys

Each key has scopes (wallets:read, transfers:write…), an environment and an optional expiry. Revoke anytime.

Idempotency

An Idempotency-Key on POST replays the original answer; a different body with the same key is refused.

Rate limits

Per key and per minute according to your plan, with X-RateLimit headers and Retry-After on 429.

Wallets

POST/walletsCreate a wallet (key_mode single, split or mpc) or one per end user with external_user_id
GET/walletsList wallets, filter by purpose, custody or external_user_id
GET/wallets/{id}/balancesBalances read from the chain
GET/wallets/{id}/transactionsIndexed on-chain history

Transfers and operations

POST/transfers/previewPolicy decision, fee and simulation; nothing is created
POST/transfersRequest a transfer (policy, approvals, screening, then signing)
GET/transfers/{id}Status, approvals, transaction hash
POST/transfers/{id}/cancelCancel before signing
POST/operationsTokens, NFTs, staking, swaps, freeze and supply lock
POST/payoutsBatch payments from one wallet

Data and compliance

GET/screeningSanctions check for any address
GET/pricesUSD prices of supported assets
GET/networksSupported networks and assets
GET/swap/quoteBest route and guaranteed minimum
GET/tokensTokens your organization issued
GET/reports/ledgerInflows, outflows and fees by period
GET/securitySecurity posture score and checks
GET/eventsEvent history (the same events as webhooks)

Errors use one shape: { "error": { "type", "code", "message", "request_id" } }. Every field is in the OpenAPI specification.

TypeScript SDK

One dependency-free ES module for Node.js 18+ with full types, automatic retries on network errors and 5xx, idempotency keys and webhook verification.

import { Chainvara } from "./chainvara.js";
const cv = new Chainvara(process.env.CHAINVARA_API_KEY);

// A deposit wallet for a customer.
const wallet = await cv.wallets.create({
  network: "solana", external_user_id: user.id,
});

const req = { wallet_id: treasury.id, asset: "USDC",
  amount: "250", destination: "@partner" };
const preview = await cv.transfers.preview(req);
if (preview.decision.outcome !== "deny") {
  await cv.transfers.create(req, { idempotencyKey: order.id });
}

Signed webhooks

Every event is POSTed to your https endpoint with a FOS-Signature: t=…,v1=… header: an HMAC-SHA256 of the timestamp and the raw body with your endpoint secret. Deliveries are retried with backoff and never sent to private addresses.

transfer.createdtransfer.approvedtransfer.rejectedtransfer.blockedtransfer.submittedtransfer.confirmedtransfer.failedtransfer.canceledtransfer.requires_reviewtransaction.detecteddeposit.receivedreconciliation.case_openedautomation.alertexecution.paused
import { verifyWebhook } from "./chainvara.js";

app.post("/webhooks/chainvara", express.text({ type: "*/*" }), async (req, res) => {
  const event = await verifyWebhook(req.body, req.get("FOS-Signature"),
    process.env.CHAINVARA_WEBHOOK_SECRET);   // throws if forged or replayed
  if (event.type === "transfer.confirmed") await markPaid(event.data.id);
  res.sendStatus(200);
});

Go further

Get your sandbox key

Free on public test networks, with the same API, policies and webhooks as production.