API Reference

OpenAPI 3.1 spec + @hundi/api-client SDK

The OpenAPI 3.1 specification at /openapi.json is the source of truth for the Hundi gateway. The TypeScript SDK @hundi/api-client is the reference implementation — every customer-facing endpoint is wrapped with typed methods, idempotency keys, and optional HMAC signing.

Spec · OpenAPI 3.1

api.hundi.network/openapi.json

Machine-readable. Generate clients in any language via openapi-generator-cli, oapi-codegen, or equivalent. Schema includes 25 endpoints across quotes, transactions, principals (Trust Registry V1), agents (Mode B), ISO 20022 ingress + egress, and audit log proofs.

Browse interactively at /docs (Swagger UI).

SDK · TypeScript

@hundi/api-client

Reference implementation. HundiClient wraps fetch with typed methods, generates idempotency keys (UUIDv4) on POST, and signs HMAC-protected mutations when credentials are supplied. Errors raise HundiApiError with the parsed { ok: false, code, message } envelope plus status code.

Node 18+. ESM. Apache-2.0. Source mirrors the OpenAPI 3.1 contract — bytes-for-bytes compatible with any other generated client.

Install

The SDK is published to npm as @hundi/api-client. For air-gapped or offline institutional environments, a versioned tarball is available at the stable URL below.

# npm / pnpm / yarn — preferred
npm  add @hundi/api-client
pnpm add @hundi/api-client
yarn add @hundi/api-client

# Versioned tarball — air-gapped fallback
curl -sLO https://docs.hundi.network/sdk/hundi-api-client-0.1.0.tgz
pnpm add ./hundi-api-client-0.1.0.tgz

# Codegen from OpenAPI spec — any language
npx @openapitools/openapi-generator-cli generate \
  -i https://api.hundi.network/openapi.json \
  -g python \
  -o ./hundi-client

Current version: 0.1.0. Direct download: hundi-api-client-0.1.0.tgz (18 KB, includes dist/ + .d.ts + sourcemaps).

Quickstart — TS

Read-only flows (quotes, transactions, audit proofs) work without credentials. Mutating routes require HMAC signing when the gateway is in HMAC_ENFORCEMENT_MODE=required; in optional mode they accept either signed or unsigned requests, and in off mode HMAC is ignored. Production runs required.

Construct the client

import { HundiClient, HundiApiError } from '@hundi/api-client';

// Unauthenticated — reads only
const client = new HundiClient({
  baseUrl: 'https://api.hundi.network',
});

// Authenticated — HMAC-signs mutating routes
const authedClient = new HundiClient({
  baseUrl: 'https://api.hundi.network',
  credentials: {
    apiKey: process.env.HUNDI_API_KEY!,
    secret: process.env.HUNDI_API_SECRET!,
  },
});

Create a quote + accept

const { quote, risk } = await client.createQuote({
  pair: { base: 'USD', quote: 'INR' },
  side: 'buy',
  notional_base: '10000.00',
  principal_did: 'did:hundi:0xabc...',
  beneficiary_did: 'did:hundi:0xbenef...',
});

// The risk envelope carries the parallel-gate decision (sanctions, KYC,
// limits, agent_scope, velocity). A denial returns 403 with risk.decision
// = 'rejected' and full per-check detail.
if (risk.decision === 'rejected') {
  console.error('Quote rejected:', risk.reasons);
} else {
  const { transaction } = await authedClient.acceptQuote(quote.id, {
    principal_did: 'did:hundi:0xabc...',
    beneficiary_did: 'did:hundi:0xbenef...',
  });
  console.log('Transaction id:', transaction.id);
}

Poll transaction status + audit chain

const tx = await client.getTransaction(transactionId);
// tx.status: 'pending' | 'submitting' | 'submitted' |
//            'finalized' | 'failed' | 'blocked' | 'cancelled'

const auditResponse = await client.getTransactionAudit(transactionId);
// auditResponse.events: ordered audit_log entries for this transaction —
// includes IVMS101 packet, sanctions screening result, ZK facts, both
// XRPL hashes (EscrowCreate + EscrowFinish) once finalized.

// For real-time updates instead of polling, subscribe to the WS feed:
// wss://api.hundi.network/v1/stream/events?kinds=transactions.finalized,transactions.blocked

Regulator-grade proof for an audit row

const proof = await client.getAuditProof(auditRowId);
// proof: {
//   leaf_hash,           // sha256(canonical_bytes)
//   leaf_index,
//   proof: [             // Merkle inclusion path
//     { sibling, position: 'left' | 'right' },
//     ...
//   ],
//   root_hash,           // daily Merkle root for proof.date
//   canonical_bytes,     // exact bytes the leaf was hashed from
//   xrpl_anchor_tx_hash, // on-chain anchor (mainnet or testnet)
//   xrpl_ledger_index,
//   anchored_at,
// }
//
// Independent verification: rehash canonical_bytes, walk the proof to
// the root, then fetch the XRPL tx and compare its hundi/audit/root
// memo. The verify-audit CLI in the Hundi repo demonstrates the full
// algorithm in ~50 lines.

Quickstart — curl

Any language can integrate via raw HTTP. The endpoints are JSON over HTTPS; mutating routes require an X-Idempotency-Key header (UUIDv4 recommended) and, when HMAC is enforced, the X-Hundi-API-Key / X-Hundi-Timestamp / X-Hundi-Signature triple.

# Public read-only request
curl -s https://api.hundi.network/v1/transactions?limit=10 | jq

# Authenticated request (HMAC enforcement: required)
TS=$(date -u +%Y-%m-%dT%H:%M:%S.000Z)
BODY='{"pair":{"base":"USD","quote":"INR"},"side":"buy","notional_base":"10000.00"}'

# Canonical signing input: METHOD\nPATH\nTIMESTAMP\nBODY
INPUT=$(printf 'POST\n/v1/quotes\n%s\n%s' "$TS" "$BODY")
SIG=$(printf '%s' "$INPUT" | openssl dgst -sha256 -hmac "$HUNDI_API_SECRET" -hex | awk '{print $2}')

curl -s -X POST https://api.hundi.network/v1/quotes \
  -H "Content-Type: application/json" \
  -H "X-Idempotency-Key: $(uuidgen)" \
  -H "X-Hundi-API-Key: $HUNDI_API_KEY" \
  -H "X-Hundi-Timestamp: $TS" \
  -H "X-Hundi-Signature: $SIG" \
  -d "$BODY"

HMAC enforcement

The gateway runs in one of three modes. The active mode is exposed at GET /v1/auth/whoami.

off

No validation

HMAC headers ignored. Test environments only.

optional

Validate when present

Signed requests validated. Unsigned requests accepted. Soft-launch mode for migrating existing institutional clients.

required

Reject unsigned

Every mutation must sign. Revoked keys reject. V1 GA production mode.

Applied to /v1/quotes, /v1/quotes/:id/accept, /v1/principals, /v1/agents and their revocations, /v1/transactions/:id/co-sign, and /v1/iso20022/pain001. Freshness window: ±5 minutes from server clock. Constant-time signature compare.

ISO 20022 (bank-grade ingress + egress)

Tier-1 banks integrate via standard ISO 20022 messages — no custom client required. Inbound: a pain.001 credit transfer initiation triggers the engine quote pipeline; outbound: pacs.002 status, pacs.008 credit transfer, and camt.054 debit/credit notification close the loop.

POST

/v1/iso20022/pain001

Accepts XML credit transfer initiation. Namespace 09/10/11. V1 single-payment (one PmtInf / one CdtTrfTxInf). The Hundi V1 extension lives in RmtInf.Ustrd as HUNDI/PAIR/USD/INR/SIDE/buy. Idempotency keyed on EndToEndId. Returns pacs.002 ACSP with HUNDI_QUOTE_ID in StsRsnInf.AddtlInf.

GET

/v1/iso20022/transactions/:id/pacs008 + /camt054

Pull-based egress for finalized settlements. pacs.008 returns the FIToFICustomerCreditTransfer (XRPL EscrowFinish hash threaded through RmtInf as the cover reference). camt.054 returns the debit notification (BkTxCd PMNT/ICDT/XBCT). Both walk the audit chain to reconstruct the original EndToEndId and IVMS101 packet.

Endpoint reference

The SDK methods map 1:1 onto gateway endpoints. Detail pages document the request / response shape of each.

Real-time events

Instead of polling, subscribe to the WebSocket feed for quote + transaction lifecycle events. Filters by kinds, pair, or principal_did.

// Browser or Node; the SDK does not yet wrap this — use a WS library
import WebSocket from 'ws';

const ws = new WebSocket('wss://api.hundi.network/v1/stream/events');

ws.on('open', () => {
  ws.send(JSON.stringify({
    type: 'subscribe',
    topic: 'events',
    kinds: ['transactions.finalized', 'transactions.blocked', 'co_sign.held'],
    pair: 'USD/INR',
  }));
});

ws.on('message', (data) => {
  const msg = JSON.parse(data.toString());
  if (msg.type === 'event') {
    console.log(msg.kind, msg.payload);
  }
});

// 30s heartbeat; reply to ping with pong. Reconnect with exponential
// backoff + jitter on connection drop.

Error envelope + status codes

Every non-2xx response from the gateway carries a structured error envelope. The SDK raises HundiApiError with status, code, and the parsed envelope.

try {
  await authedClient.acceptQuote(quoteId, { principal_did: '...' });
} catch (err) {
  if (err instanceof HundiApiError) {
    if (err.code === 'RISK_REJECTED') {
      // Risk gate denied — see err.envelope for per-check detail
    } else if (err.code === 'KYC_REFRESH_OVERDUE') {
      // Principal's annual KYC refresh is past due; settlement-time block
    } else if (err.code === 'AGENT_NOT_AUTHORISED') {
      // Mode B: (agent_did, pair) not in the agent's scope
    } else {
      // err.status, err.code, err.envelope, err.bodyText all available
    }
  }
}

Spec, SDK, and these docs are versioned with the gateway. Drift between the OpenAPI spec at /openapi.json and these pages is a bug — report at platform@hundi.network.