Documentation · v0.4

Meridian documentation

Meridian lets engineering teams express treasury policy as code, deploy it to TON and USD₮ rails under a non-custodial multisig, and reconcile it against an on-chain audit trail. This is the primary developer reference. If you have not yet been granted workspace access, apply for access first.

Status Meridian is in private preview (cohort 02). The SDK and HTTP API documented here are v0.4. Breaking changes between v0.4 and v1.0 will be enumerated in the changelog with codemods where applicable.

Quickstart

Get from a fresh workspace to a deployed policy in roughly five minutes.

1. Install the SDK

npm install @meridian/sdk
npx meridian login
npx meridian init treasury

2. Author a policy

// treasury/policies/vendor-payouts.ts
import { meridian, USD } from "@meridian/sdk";

export const policy = meridian.policy({
  name: "weekly-vendor-payouts",
  authorizers: ["finance-multisig"],
  schedule: "every friday at 14:00 utc",
  limits: { perRun: USD(500_000) },
  execute: async ({ ledger, pay }) => {
    const invoices = await ledger.openInvoices({ approved: true });
    for (const inv of invoices) {
      await pay(inv.counterparty, inv.amount, { rail: "usdt-ton" });
    }
  },
});

3. Simulate against forked TON state

npx meridian simulate ./treasury/policies/vendor-payouts.ts \
  --fork mainnet \
  --balance "USDT:1000000"

4. Deploy to staging, then production

npx meridian deploy ./treasury/policies/vendor-payouts.ts --env staging
npx meridian promote weekly-vendor-payouts --to production

Promotion to production opens an approval in the console requiring multisig sign-off on the compiled policy hash.

Workspaces & authentication

Each Meridian client receives a workspace scoped to a single legal entity. Inside a workspace you have one or more environments (typically staging and production), each with its own multisig, counterparty registry, and policy set.

SDK and CLI calls authenticate using a workspace API key plus a signed device. API keys are scoped to a single environment and are never written to disk in plaintext — the CLI delegates signing to a paired hardware key or your OS keychain.

ScopeCreated byLifespan
Workspace keyConsole adminRotated quarterly
Environment keySDK meridian login30 days, rolling
Device keyHardware-pairedUntil revoked

Policies

A policy is the unit of work in Meridian. It is a typed, version-controlled function that emits a sequence of payment instructions when it executes. Policies are deterministic: a policy compiled at hash H emits the same instructions every run, modulo external state.

A policy has five components:

  • name — the canonical identifier inside a workspace. Cannot be changed after first deployment.
  • authorizers — the named multisigs that must co-sign every instruction this policy emits.
  • schedule — cron expression, natural-language schedule, or webhook trigger.
  • limits — hard caps per run, per counterparty, and per period. Enforced at compile time by the verifier.
  • execute — the body that runs against the ledger and emits instructions.

Instructions

An instruction is a single signed payment payload. Instructions move through five states: drafted, awaiting_signatures, broadcast, settled, reconciled. The protocol guarantees that no instruction transitions from awaiting_signatures to broadcast without the full quorum present.

Authorizers & multisig

Authorizers are named multisigs registered to a workspace. Meridian supports four authorizer types:

  • Safe{Wallet} on TON — multisig signed in-app or via WalletConnect.
  • Fireblocks MPC — co-signer model with HSM-backed signing.
  • Hardware — Ledger and Trezor signers in 2-of-3 or 3-of-5 configurations.
  • Hybrid — combinations of the above (Fireblocks + Ledger is common).

The protocol's executor key is never an authorizer. It can only co-broadcast a transaction whose value-bearing payload has already been signed by the client's authorizers.

Counterparties

A counterparty is any external entity to which your treasury sends funds or from which it receives funds. Every counterparty is registered before the first instruction settles, and registration triggers KYB via Sumsub for entity-level counterparties or sanctions screening via Chainalysis KYT for individual addresses.

Reconciliation

Reconciliation is automatic. The reconciliation indexer consumes the TON ledger and matches every settled instruction back to its originating policy and authorizer set. Signed reconciliation reports are published per policy on a fixed cadence (default: weekly) and via webhook on every settlement.

SDK · install

npm install @meridian/sdk          # or
pnpm add @meridian/sdk             # or
bun add @meridian/sdk

Runtime support: Node.js 20+, Bun 1.1+, Deno 1.40+. The SDK is reproducible-build certified and signed with Sigstore.

meridian.policy()

The policy() factory is the primary entrypoint. It returns a CompiledPolicy which can be deployed to a workspace.

type PolicyArgs = {
  name: string;
  authorizers: string[];
  schedule: string | CronExpression | WebhookTrigger;
  limits?: PolicyLimits;
  execute: (ctx: PolicyContext) => Promise<void>;
};

pay() & ledger

Inside the execute function, the policy context exposes ledger (read-only) and pay (instruction-emitting). All pay calls are queued and atomically authorized at end-of-run.

await pay(counterpartyId, amount, {
  rail:     "usdt-ton" | "ton",
  memo?:   string,
  priority?: "normal" | "high",
});

Simulate & deploy

Simulation forks TON state at a chosen block, applies any --balance overrides, and runs the policy without touching production keys. Output is a structured trace including every instruction, the required signers, and the projected fee.

HTTP API · authentication

The HTTP API lives at https://api.meridian.fi/v1. All requests require a Bearer token issued from the console.

Authorization: Bearer mrn_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Test-mode keys are prefixed mrn_test_ and resolve to the staging environment. Test-mode instructions never settle on mainnet.

Instructions endpoints

POST/v1/instructions

Submit a payment instruction for multisig review. Body must include policy, amount, currency, rail, counterparty.id, and an idempotency_key.

GET/v1/instructions/:id

Read instruction status, signatures, and on-chain proof.

GET/v1/instructions?status=awaiting_signatures

List instructions, filterable by status, policy, counterparty, created_after.

Policies endpoints

POST/v1/policies
GET/v1/policies
GET/v1/policies/:name

Balances

GET/v1/balances

Returns current balances grouped by asset and policy. All values are reconciled against on-chain state at request time; the response includes a reconciled_at timestamp.

Counterparties

POST/v1/counterparties
GET/v1/counterparties/:id

Audit log

GET/v1/audit/log

Stream the full on-chain audit log. Supports server-sent events for live tail. Every event includes the policy hash, the authorizer quorum, and the on-chain transaction reference.

Webhook events

Subscribe to webhooks per workspace. Each event is a JSON document signed with the workspace's Ed25519 key.

EventDescription
instruction.draftedA policy run produced an instruction.
instruction.signedAn authorizer signed.
instruction.settledSettled on TON. Includes tx_hash and block.
instruction.failedSettlement attempt failed; queued for retry or manual review.
policy.deployedA new policy version was promoted.
reconciliation.reportA signed reconciliation report is available.

Webhook signing

Every webhook includes X-Meridian-Signature (Ed25519, base64) and X-Meridian-Timestamp. Reject any payload older than 300 seconds. The signing key is rotatable per workspace via the console.

import { verify } from "@meridian/sdk/webhook";

const ok = verify({
  payload:   req.rawBody,
  signature: req.headers["x-meridian-signature"],
  timestamp: req.headers["x-meridian-timestamp"],
  publicKey: process.env.MERIDIAN_WEBHOOK_KEY,
});

Retries

Failed deliveries are retried with exponential backoff up to 24 hours. After that, events land in a dead-letter queue inspectable from the console. The retry schedule: 30s, 5m, 30m, 2h, 6h, 24h.

Errors

The HTTP API uses standard status codes plus a structured error body.

StatusCodeMeaning
400invalid_requestThe payload is malformed or missing required fields.
401unauthorizedAPI key missing, expired, or revoked.
403policy_violationThe instruction would breach a policy limit.
404not_foundThe resource does not exist within this workspace.
409idempotency_conflictIdempotency key reused with a different payload.
422counterparty_unscreenedCounterparty has not completed KYB or sanctions screening.
429rate_limitedWorkspace exceeded its per-second burst.
503executor_pausedExecutor is paused due to RPC or oracle divergence.

Rate limits

The default rate limit is 60 requests per second per workspace, with a 200-request burst. Limits are enforced per environment. Audit-log streams do not count against the rate limit. Higher limits are available on request.

Idempotency

Every POST endpoint accepts an idempotency_key in the body. Reuse the same key for safe retries — Meridian returns the original response. Keys are scoped to a workspace and retained for 7 days.

Cookbook

Patterns the design-partner cohort has converged on.

Bi-weekly payroll with cooldown

meridian.policy({
  name: "payroll-bi-weekly",
  schedule: meridian.cron("0 12 * * 4/2", "UTC"),
  limits: {
    perRun: USD(300_000),
    cooldownHours: 336,
  },
  execute: async ({ pay }) => { /* … */ },
});

Threshold-driven FX rebalance

meridian.policy({
  name: "ton-rebalance-threshold",
  schedule: meridian.onBalance({ asset: "TON", above: USD(5_000_000) }),
  execute: async ({ ledger, swap }) => {
    const excess = await ledger.excessOver("TON", USD(3_000_000));
    await swap("TON", "USDT", excess, { venue: "licensed-fx-desk" });
  },
});

Webhook-driven receivable

meridian.policy({
  name: "recurring-receivable",
  schedule: meridian.onWebhook("invoice.issued"),
  execute: async ({ event, expect }) => {
    await expect(event.amount).from(event.payerId).within("7d");
  },
});

Changelog

VersionDateNotes
v0.4.22026-05-08Webhook signing key rotation via console.
v0.4.12026-04-22Idempotency window extended to 7 days.
v0.4.02026-04-01onBalance trigger; swap() primitive (private preview).
v0.3.52026-02-18SDK reproducible builds. Sigstore verification enforced.
v0.3.02025-11-12Counterparty KYB pipeline (Sumsub).

Need something not covered here? Email se@meridian.fi. The SDK is open source at github.com/meridian-fi/sdk (private during preview — request access for the link).