Day 0 — Connect Stripe
OAuth into Stripe with read_only base scope. Axiru pulls 90 days of history into shadow-mode replay. No code changes in your app.
The technical concreteness pass. What you'll wire, what scopes we ask for, how long it takes, and what happens when Axiru is unreachable. No marketing arm-waving.
Most teams reach enforcing-on-refunds in ~10 hours of engineering across two weeks. The first week is policy tuning in shadow mode; the second is flipping the switch.
OAuth into Stripe with read_only base scope. Axiru pulls 90 days of history into shadow-mode replay. No code changes in your app.
Walk the replay with your team. Tune policies on observed history before any line of code is changed. Free for 90 days.
Add the ~10-line decide call in front of refunds (or your first chosen action). Default is observe-only — the call returns advisory, your code still executes normally.
Once shadow telemetry shows the policy is doing what you want, flip the action to enforce. Deny outcomes now block the Stripe call.
Payouts, transfers, app-fee refunds, disputes — same decide shape, different `action`. Onboard one at a time.
The integration shape is intentionally boring. Bearer auth, idempotency-keyed, allow/deny/review semantics. If you can call Stripe, you can call Axiru.
From your backend, before stripe.refunds.create.
// Before issuing a refund, ask Axiru if it should happen.
const decision = await fetch("https://api.axiru.com/api/v1/decisions", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.AXIRU_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
intent: {
kind: "refund", // refund | credit | adjustment
amount_cents: 12_500,
currency: "USD",
stripe_connection_id: connId,
metadata: { order_id },
},
context: {
customer_id: customerId,
customer_tenure_days: 412,
reason_code: "requested_by_customer",
},
idempotency_key: refundRequestId, // safe to retry
}),
}).then((r) => r.json());
if (decision.outcome === "allow") {
await stripe.refunds.create({ charge: chargeId, amount: 12_500 });
} else if (decision.outcome === "deny") {
return { error: decision.reason_code, message: decision.message };
} else if (decision.outcome === "review") {
return { pending: true, approval_id: decision.approval_id };
}From an LLM agent, via the axiru.decisions.create MCP tool.
// MCP-flavored equivalent — same payload, agent-callable.
const result = await mcp.callTool("axiru.decisions.create", {
intent: {
kind: "refund",
amount_cents: 12_500,
currency: "USD",
metadata: { order_id },
},
context: {
customer_id: customerId,
reason_code: "requested_by_customer",
},
idempotency_key: refundRequestId,
});
// result.outcome in { "allow", "deny", "review" }
// result.policy_version, result.decision_idFull request/response reference lives in the decisions API docs. Every decision returns a decision_id and policy_version that land in the decision ledger for audit. Default rate limit is 100 requests/minute per API key, fail-closed when Redis is unreachable.
Most customers start with the REST decide call on refunds. Agent-heavy teams prefer the MCP tool. Webhook is the observe-only fallback for legacy code paths.
POST /api/v1/decisions with a Bearer API key. Returns within 80ms p95. Use this if you're calling from your own backend.
Same payload exposed as `axiru.decisions.create` over MCP. Use this if an LLM agent is the caller and you don't want it touching Stripe directly.
Drop-in option for legacy code paths where adding a pre-flight call isn't practical. We observe and alert on the resulting Stripe event, but we cannot block.
We follow least-privilege. Read-only is enough to start; write scopes are requested only for the actions you choose to enforce.
Inventory accounts, balances, charges, refunds, payouts, app fees.
Required for shadow-mode replay and audit. No money is moved with read-only scopes.
Create and decline refunds via the Refunds API.
Required for refund enforcement. Without it, Axiru can decide but not execute.
Create, reverse, or hold payouts to connected accounts.
Required for payout enforcement and emergency holds.
Create or reverse Connect transfers between platform and connected accounts.
Required for marketplace transfer enforcement and clawbacks.
Respond to and submit evidence for disputes.
Required when Evidence Agent submits evidence packets on your behalf.
Refund application fees on Connect charges.
Required for app-fee refund enforcement on platform charges.
Tokens are stored encrypted and rotated on the key-rotation rehearsal cadence. We never request a scope until the corresponding action is being enforced.
Money-path infrastructure cannot quietly fail. Defaults are conservative — money-out actions hold; advisory and time-sensitive actions degrade gracefully. Every default is per-policy overridable.
Money leaving the business. If Axiru is unreachable, the refund is held for human review rather than auto-executed. Configurable per policy.
Money leaving the platform to connected accounts. Default hold on unreachable; explicit allow-list to fail-open per program.
Connect transfers between platform and connected accounts. Default hold; same per-policy override available.
App-fee refunds reduce platform revenue. Hold on unreachable.
Missing the Stripe response window is worse than submitting on best-available evidence. Evidence Agent falls back to the last good packet and emits a degraded-mode signal.
Pre-enforce, the decide call is advisory only. A failed advisory never blocks your code path.
We test these defaults with a continuous fail-closed contract suite (T-044, shipped). The roadmap tracks expansion of that suite to every new rail before it ships.
The first 90 days are free and read-only. You'll have replayed history and tuned policy before you ever add a line of code.
Start in shadow mode first. Move to live enforcement later.