Search the docs or ask a question /
Concept

Policies

Deterministic rules a program applies, with an SLA on every breach

Get started with policies

A policy is one control a program applies: a set of rules, made from a template and owned by exactly one program. Packs supply the templates and are chosen per program when it is created; every policy stays editable after. A policy judges what its program’s source delivers: the events on its subscribed streams, or, on a hosted program, the step of the flow it is bound to.

A rule is one of seven kinds: threshold, velocity, ratio, measure, binary, list_match and composite.

Soft & hard limits

A threshold, velocity, ratio or measure rule carries a hard limit, and optionally a soft one that warns while there is still time to act. A value at or past the soft limit raises a Soft breach; at or past the hard limit, a Hard breach. A binary or list_match rule carries a fixed severity instead, and a composite rule a soft and a hard score. The breach severity picks the SLA hours on the exception.

Validated at save. A soft limit beyond its hard limit is refused when the policy is saved: “Soft limit (x) must warn before the hard limit (y).”

Routes

Each band also routes the breach: No action, In review or Decline, and a Decline carries a decline type, Retry or Final. The route is what a check() answers: In review answers Hold, Decline answers Deny, and anything else Allow.

Units

A money limit names a currency the platform prices in: AUD, USD, EUR, GBP, CAD, NZD, SGD or JPY. Any other is refused at save: “‘X’ is not a currency this platform prices in.” Ratio, day and count limits carry their unit instead; nothing converts into them.

Packs & templates

Three nouns, in order of how much they know about a specific business:

  • Pack: a curated set of templates. Available today: Sanctions Screening, Transaction Monitoring and Concern bundles. Customer & identity, Travel rule and Fraud are drafts and cannot be chosen.
  • Template: one named control inside a pack. It carries default rules, a policy category, an optional link to a risk indicator, an optional event type or flow step it binds to, and where one exists, the regulation it maps to.
  • Policy: a template adopted into a program, with the limits the team set. Editing a policy never edits its template.

A template marked Draft shows “Not available yet” in the program wizard and cannot be chosen.

Sanctions Screening

Matches the counterparty on every recorded event that names one, and both sides of every chain transfer, against the lists the account maintains. The match is exact, and a list that cannot be read fails closed. The hard band declines with decline type Final; the team can change the route to In review. No external sanctions or watchlist source is connected, and indirect exposure is not in this build.

Transaction Monitoring

Large outflow and large inflow, velocity, cumulative outflow per wallet over 24 hours, structuring by counterparty over a 60-minute window (chain transfers only), new counterparty, dormant reactivation, high-value outbound review and a counterparty allowlist. Every template ships default limits, which the team edits per policy.

Concern bundles

Holds the controls for issuers and treasuries: unauthorized_mint (a mint or burn whose authorising key is not on the approved-minters list), reserve_ratio (circulating supply against reserves on each reserve.snapshot, soft 0.98, hard 1.00), reconciliation_gap (an onchain mint with no recorded mint of the same txHash, found by a sweep every 90 seconds), privileged_action (admin.action), asset_concentration and stablecoin_depeg.

Check before acting

check() asks the program’s policies about an action before it moves, in the shape a later track() of the same action takes, and records the answer:

payout.mjs
const payout = { amount: "290000.00", asset: "USDC", chain: "polygon", toAddress: "0x…", correlationId: "payout_8812" };

const answer = await hira.check("payout", payout);
if (answer.verdict !== "Allow") {
  // "Hold": a band routed to In review; answer.poll() asks again under the same key
  // "Deny": a band routed to Decline, or reasonCode "NoActivePolicy" when nothing watches the stream
} else {
  const txHash = await sendPayout();     // the app's own payout
  hira.track("payout", { ...payout, txHash });
}

The key needs the Transaction monitoring scope. The API reference lists the answer’s fields.