Customer developer docs

Run your first guarded request

Follow one request from SDK call to approval, denial, or manual review using the customer-visible fields and responses.

Run your first guarded request

This page walks through one customer-facing request flow using a Stripe-style payment example. The goal is to show the fields you send, the responses you must handle, and where your team looks next when a request is approved, denied, or paused for review.

Goal

Use this page when you are ready to send your first real request to Ledgix after creating an API key and uploading policy content.

The request you send

Ledgix needs the exact tool name and the exact arguments you plan to execute. Keep the payload focused on the real action, not a generic plan or summary.

FieldTypeRequiredDescription
tool_namestringYesThe action Ledgix is authorizing, such as create_stripe_payment or stripe_refund.
tool_argsobjectYesThe arguments that will be used if the action is allowed.
agent_idstringYesThe agent or service identity you want recorded with the request.
session_idstringNoA correlation ID for the broader workflow or user session.
context.policy_idstringNoOptional hint for the policy you want Ledgix to apply first.
http
POST /request-clearance HTTP/1.1
Host: vault.example.com
Content-Type: application/json
X-Vault-API-Key: sk_prod_example

{
"tool_name": "create_stripe_payment",
"tool_args": {
  "amount": 249.99,
  "currency": "USD",
  "customer_id": "cus_123",
  "payment_method_id": "pm_123",
  "order_event_id": "ord_evt_2048",
  "reasoning": "Charge matches a completed order event."
},
"agent_id": "payments-agent",
"session_id": "checkout-42",
"context": {
  "policy_id": "payments-prod"
}
}

The responses you must handle

Ledgix returns one of four statuses:

FieldTypeRequiredDescription
approvedterminalYesThe action is allowed. An approval token is included when the response is approved.
deniedterminalYesThe action should not run. Use the reason for logs, UI, or operator feedback.
pending_reviewnon-terminalYesThe request needs a human reviewer before it can continue.
processingnon-terminalYesLedgix accepted the request but has not returned a final answer yet.

Example approved response:

text
{
  "status": "approved",
  "approved": true,
  "requires_manual_review": false,
  "token": "eyJhbGciOiJFZERTQSIsImtpZCI6InZhdWx0LWtleS0xIn0...",
  "reason": "The payment matches the uploaded policy and the threshold.",
  "request_id": "8ee2d480-4e23-49c5-9869-a0247e806e1c",
  "confidence": 0.93,
  "minimum_confidence_score": 0.80
}

Example pending-review response:

text
{
  "status": "pending_review",
  "approved": false,
  "requires_manual_review": true,
  "token": null,
  "reason": "The action may be valid, but the confidence score is below the current threshold.",
  "request_id": "8ee2d480-4e23-49c5-9869-a0247e806e1c",
  "confidence": 0.74,
  "minimum_confidence_score": 0.80
}

Polling when the result is not final

If you call the HTTP API directly, poll GET /clearance-status/{request_id} until the request resolves to approved or denied.

text
GET /clearance-status/8ee2d480-4e23-49c5-9869-a0247e806e1c HTTP/1.1
Host: vault.example.com
X-Vault-API-Key: sk_prod_example

Both SDKs already handle polling for processing and pending_review for you. Use the direct status endpoint only when you want custom behavior around long-running or human-reviewed requests.

Using the approval token

When the request is approved, Ledgix returns a short-lived token for that specific action. Most teams either forward that token to a protected gateway or attach it to the downstream call they are protecting.

text
if (clearance.approved && clearance.token) {
  await fetch(process.env.STRIPE_GATEWAY_URL!, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      Authorization: `Bearer ${clearance.token}`,
    },
    body: JSON.stringify({
      amount: 249.99,
      customer_id: "cus_123",
    }),
  });
}

The gateway then injects X-Ledgix-* headers upstream. See /security/cryptography-and-tokens for the security model.

Where the ledger write happens

For synchronous terminal outcomes, Vault writes the decision to the tenant ledger before returning success. That write contains:

  • the request identifiers
  • the tool name
  • the tool argument payload
  • the reason, citations, and evidence chunks
  • the confidence score
  • the approval outcome
  • the computed event_hash
  • the computed leaf_hash
  • the signed receipt payload and signature

The event is durable at that point, but it may not yet have a leaf_index or checkpoint_id. Those arrive when the background sealer sequences the event into the Merkle tree.

Verifying the same request later

Once the event is sealed, you can fetch the full proof bundle:

text
GET /ledger/proof/bundle?request_id=8ee2d480-4e23-49c5-9869-a0247e806e1c HTTP/1.1
Host: vault.example.com
X-Vault-API-Key: sk_prod_example

The bundle includes:

  • the full event record
  • the inclusion proof
  • an optional consistency proof to a later checkpoint
  • the relevant verification keys

That is the artifact you want for customer-side or auditor-side offline verification.

Full example with the SDKs

TypeScript
import { configure, autoInstrument, currentToken, currentClearance } from "ledgix-ts";
import { LedgixClient } from "ledgix-ts";

const rawTools = {
async createStripePayment(amount: number, customerId: string, paymentMethodId: string) {
  const token = currentToken();           // A-JWT for this approval
  const clearance = currentClearance();   // Full ClearanceResponse if needed
  return { authorized: true, token, requestId: clearance?.requestId };
},
};

// Configure once at startup
configure({ agentId: "stripe-agent-demo" });

// Instrument the module based on ledgix.json
const tools = autoInstrument(rawTools);

// Call the instrumented tool
const result = await tools.createStripePayment(249.99, "cus_farhan_approved_2048", "pm_demo_visa_4242");

// Verify the ledger proof after the fact
const client = new LedgixClient();
const bundle = await client.fetchLedgerProofBundle(result.requestId!);
const verification = await client.verifyLedgerProofBundle(bundle);
console.log(verification);

How it fails

Where your team looks next

  • Approved or denied requests show up in the customer ledger and advanced verification APIs.
  • Pending-review requests appear in the customer dashboard review queue.
  • Reviewers can approve or deny a paused request from the dashboard or by calling the review decision API.

Practical handling rules

  • Treat pending_review as an expected workflow state, not a transport error.
  • Log request_id on every outcome so your team can trace a request in the dashboard later.
  • Keep the tool arguments stable between approval and execution. If the payload changes, request clearance again.
  • If you use the SDK wrappers, test one denied request on purpose so you know how your app behaves when Ledgix blocks the action.