Skip to content

Get started

Quickstart in five minutes

One command creates an agent with a payment rule. Then watch Immiscible send one payment to a person, allow it once they approve, and refuse a lookalike supplier on its own.

To see it work first, with no account and nothing leaving your machine, run npx immiscible try: an action allowed, a payment held for you to approve, a lookalike supplier denied, and the signed receipt verified. Then:

You need an Immiscible workspace (sign up at https://immiscible.fly.dev/signup, or run your own), Node 22.13 or later, and curl. Not an engineer? For finance teams is the same start without any code.

#1. Create the agent

In your agent’s project.

It signs you in through the browser, creates the agent and its rule, writes IMMISCIBLE_URL and IMMISCIBLE_AGENT_KEY to .env (and .env to .gitignore), prints the code for the SDK it finds, and ends with a live test call.

In a workspace with more than one owner, a new rule waits for a second owner to confirm it, and the end reads like this instead.

init then exits with code 10: the agent and its key are ready, and the rule takes effect once the other owner confirms it in the console. Run npx immiscible init again afterwards and the test call is made afresh under the confirmed rule.

The rule’s limits come from your workspace’s templates, so yours may differ. Every option, and what to do in CI, is in the CLI. Then load the two variables into your shell.

Shell
npx immiscible init --name "Invoice agent" --purpose pays_invoices
Output
✓ Created Invoice agent in Quayside
  Rule: Pays up to £10,000 at a time and £50,000 a month. Payments above £5,000 need a person. A supplier it has not paid before needs a person.
✓ Added IMMISCIBLE_URL and IMMISCIBLE_AGENT_KEY in .env
✓ Governed by Immiscible: Invoice agent (Quayside)
Output
! Waiting for another owner to confirm the rule for Invoice agent (Quayside). Until then everything it asks for is refused.
  The connection works: the test payment reached Immiscible and was refused, as it should be while the rule waits.
Shell
set -a; . ./.env; set +a

#2. Ask before paying

Before the agent pays, it says what it wants to do and what influenced it.

The agent has never paid this supplier, so a person decides.

With the SDKs, guard() (or pay() with a function) asks, waits for the person, runs your code only on allow, and settles: see the SDKs.

curl -X POST "$IMMISCIBLE_URL/v1/actions/authorize" \
  -H "authorization: Bearer $IMMISCIBLE_AGENT_KEY" \
  -H "content-type: application/json" \
  -d '{
    "type": "payment",
    "summary": "Pay Acme Supplies invoice 0931",
    "payment": {
      "amount": 125000,
      "currency": "GBP",
      "merchant": {
        "name": "Acme Supplies",
        "domain": "acme-supplies.example"
      }
    },
    "provenance": [
      {
        "source": "user",
        "detail": "invoice approved in the finance inbox"
      }
    ],
    "idempotencyKey": "inv-0931"
  }'
JSON
{
  "id": "act_b4811df1",
  "decision": "approval_required",
  "status": "pending_approval",
  "reasons": [
    "This agent has not paid acme-supplies.example before. A person must approve new merchants."
  ],
  "mandateId": "mdt_31b2a52d",
  "risk": {
    "score": 20,
    "signals": [
      {
        "id": "new_merchant",
        "severity": "medium",
        "effect": "approval",
        "detail": "This agent has not paid acme-supplies.example before. A person must approve new merchants."
      }
    ]
  },
  "approval": {
    "id": "apr_aee8d38b",
    "url": "https://immiscible.fly.dev/app/approvals/apr_aee8d38b",
    "expiresAt": "2026-10-06T13:13:32.770Z"
  },
  "expiresAt": "2026-10-06T13:13:32.770Z"
}

#3. Approve it

Open approval.url. You also get it by email, and in Slack or Teams if they are connected. Choose Approve. The agent polls until a person answers.

The receipt’s hum claim is true: a person approved this specific payment. Anyone can verify it without an account.

Shell
curl "$IMMISCIBLE_URL/v1/actions/act_b4811df1" \
  -H "authorization: Bearer $IMMISCIBLE_AGENT_KEY"
JSON
{
  "id": "act_b4811df1",
  "decision": "allow",
  "status": "allowed",
  "reasons": [
    "Approved by sam@quayside.example.",
    "This agent has not paid acme-supplies.example before. A person must approve new merchants."
  ],
  "receipt": "eyJhbGciOiJFZERTQSIs..."
}

#4. Report what happened

After paying, the agent settles the action, so the ledger holds the outcome and not only the permission.

Settling above the authorised amount is recorded as an incident and alerts the owner.

Shell
curl -X POST "$IMMISCIBLE_URL/v1/actions/act_b4811df1/settle" \
  -H "authorization: Bearer $IMMISCIBLE_AGENT_KEY" \
  -H "content-type: application/json" \
  -d '{ "status": "completed", "amount": 125000 }'

#5. Watch it ask, and refuse

Send the same request with "amount": 620000 (£6,200) and the idempotency key inv-0933. It is above the £5,000 line, so a person decides.

Now set the domain to acme-suppl1es.example (a one for the i), the source to email, and the key to inv-0934. Nobody is bothered.

A refusal is a 200 with a decision, not an HTTP error: see decisions. If the agent is an intern, a second payment to Acme also asks (tier_intern); it earns the right to pay alone on its record.

JSON
{
  "decision": "approval_required",
  "reasons": [
    "£6,200.00 is above the £5,000.00 that Pays invoices lets the agent spend without asking."
  ]
}
JSON
{
  "decision": "deny",
  "status": "denied",
  "reasons": ["acme-suppl1es.example looks like acme-supplies.example but is not it."]
}

#6. Find the kill switch

Agents, the agent, then Stop. From that moment every request from that agent is refused: its action requests are denied, ones already waiting for approval are cancelled, and its model calls and tool calls through Immiscible get 403 agent_stopped before anything is sent. Read the kill switch before you need it.

#Next

  • Govern a coding agent: Claude Code and Cursor behind the MCP proxy and the hook.
  • Decisions: every signal, and the order they combine in.
  • The SDKs: guard() wraps authorise, wait, run and settle in one call.

#Without the CLI

If you would rather not run npx, install an SDK directly (npm install @immiscible/sdk or pip install immiscible; both have no runtime dependencies) and do step 1 in the console instead. Open Agents and choose Add an agent:

  1. What does the agent do? Choose Pays invoices, and give it a name a person will recognise on their phone.
  2. Who approves? The person asked when the agent needs one. Choose Add the agent.
  3. Give this to whoever set up the agent. Open the agent’s setup page and choose Collect the agent’s key. The key is shown once.

An agent key can ask for permission and nothing else: it holds no card number, no personal data, and it cannot approve its own requests, widen a rule or lift a freeze. Set IMMISCIBLE_URL and IMMISCIBLE_AGENT_KEY yourself, then carry on from step 2.