Docs Start here

Govern one action over HTTP

Route one consequential action through KIFF Cloud and get a decision before it runs — over plain HTTP. No Go, no framework, no domain to author by hand. You’ll watch KIFF refuse a refund on an order that was never paid, then see the domain that decision came from.

KIFF decides; your code stays the executor. KIFF only governs the actions you route through it.

Base URL: https://api.kiff.dev. Every call is authenticated with a Bearer API key.

1. Get an API key

Sign in at app.kiff.dev, open Settings → API keys, and mint one. It’s shown once. Export it:

export KIFF_KEY="kiff_live_…"

2. Seed a starter domain (no authoring)

You don’t start from a blank file. Apply the refund-agno starter — a minimal order-refund domain — in one call:

curl -s https://api.kiff.dev/v1/me/domain/template \
  -H "Authorization: Bearer $KIFF_KEY" \
  -H "Content-Type: application/json" \
  -d '{"slug":"refund-agno"}'

That domain says, in plain terms: an Order moves CREATED → PAID → REFUNDED, and AUTO_REFUND is only allowed from PAID.

3. Ask KIFF to decide one action

Your refund agent is about to auto-refund order-001 — an order KIFF has no record of being paid. Ask first:

curl -s https://api.kiff.dev/v1/proposals/decide \
  -H "Authorization: Bearer $KIFF_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "id": "demo-001",
    "entity_id": "order-001",
    "entity_type": "Order",
    "action_name": "AUTO_REFUND",
    "actor_id": "refund-agent",
    "parameters": {"amount": 4900, "reason": "customer request"}
  }'

KIFF refuses it:

{
  "proposal_id": "prop_…",
  "outcome": "blocked",
  "reasons": ["state_not_allowed"],
  "message": "entity is not in a state that permits this action",
  "mode": "enforce"
}

That’s the point. The refund was blocked not because you told KIFF the order was unpaid, but because KIFF reconstructed the order’s state from its own events and the order is not PAID. A retry won’t change it. Your agent never sends the money.

Once the order is actually paid, the identical call returns:

{ "outcome": "allowed", "message": "action contract satisfied; safe to execute", "mode": "enforce" }

— and your code runs the refund.

4. See the proof

Every decision is recorded as a signed receipt — proof KIFF decided before execution. Because you threaded an id (demo-001) on the proposal, its decision receipt has a deterministic trace, decision-demo-001:

curl -s https://api.kiff.dev/v1/receipts/decision-demo-001 \
  -H "Authorization: Bearer $KIFF_KEY"

The receipt is signed and tamper-evident: what was proposed, the state it was decided against, and the outcome.

Receipts are signed by a background sweep, so the signed receipt appears within about a minute of the decision — if the fetch 404s or the list is empty, give it a moment and re-run. You can also list recent receipts with curl -s https://api.kiff.dev/v1/receipts.

5. The domain behind the decision

That decision didn’t come from a generic API — it came from a governed domain. Open it at app.kiff.dev/dashboard/domains: the entity, its lifecycle, the action contract (AUTO_REFUND allowed only from PAID), and the evidence are all there. From here you shape the domain in your codebase — Build scaffolds it to your repo, you finish it with your agent and kiff verify, then re-activate — and your agent keeps routing through the same boundary.

That’s the whole arc: start with one action, discover the domain behind it, grow into a governed backend. KIFF Cloud is paid for the governed operations flowing through that domain — not for the domains, actions, agents, or integrations themselves.

What this is and isn’t

  • KIFF returns a decision; your system executes. It does not move money, hold credentials, or run your agent.
  • It governs the actions you route through it. It can’t stop an action on a path that never asks.
  • The unit is the governed operation: one authenticated proposal evaluated against current state and the active domain contract, with a terminal outcome. Idempotent retries don’t count twice.

Next