SOXAgent Documentation

Integrate SOXAgent with your AI agents to govern financial actions with policy enforcement, audit trails, and signed evidence packs.

Base URL: https://soxagent-api.fly.dev

Getting Started

Get up and running in five steps:

  1. Create an account at app.soxagent.com
  2. Generate an API key in Settings → API Keys. Copy the key immediately — it's only shown once.
  3. Register an agent in the Agents tab. Give it an agent_id that your code will use in API calls.
  4. Create a policy in the Policies tab. Define action types, approval thresholds, and escalation rules.
  5. Submit your first authorization using the API. See the Authorization section below.

New accounts include a guided setup wizard that walks you through these steps.

Authentication

Authenticate API requests using your API key. Two header formats are supported:

Bearer token (recommended)
Authorization: Bearer sk_live_your_key_here
x-api-key header
x-api-key: sk_live_your_key_here

API keys are prefixed by environment: sk_live_ for production and sk_test_ for sandbox. Generate and manage keys in the dashboard at Settings → API Keys. See Environments for details.

Idempotency

All POST requests require an Idempotency-Key header. Use a UUID or unique request identifier. If a request is retried with the same key and body, the original response is replayed without re-execution.

Example headers
Authorization: Bearer sk_live_abc123...
Content-Type: application/json
Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000

Rate Limits

API requests are rate-limited to 1,000 requests per minute per tenant. Rate limit headers are included in every response:

  • X-RateLimit-Limit — requests allowed per window
  • X-RateLimit-Remaining — requests remaining
  • Retry-After — seconds until limit resets (when exceeded)

Environments

Every SOXAgent workspace has two isolated environments: TEST and LIVE. Policies, authorizations, and evidence are scoped to the environment determined by your API key.

EnvironmentKey prefixPurpose
testsk_test_Sandbox for development and CI. Evaluate policies without affecting production data or audit trails.
livesk_live_Production. Authorizations generate real audit evidence and are included in compliance reporting.

The environment is determined entirely by the API key used in the request. A sk_test_ key will only evaluate TEST policies and create TEST authorizations. A sk_live_ key will only evaluate LIVE policies and create LIVE authorizations. There is no cross-environment interference.

Recommended workflow

  1. Create policies in TEST and validate them with sk_test_ keys
  2. Run your agent integration tests against the TEST environment
  3. Promote policies to LIVE when ready
  4. Switch your production agents to sk_live_ keys
Test environment request
curl -X POST https://soxagent-api.fly.dev/v1/authorizations \
  -H "Authorization: Bearer sk_test_your_key" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{ "action": { "type": "refund_approve", "amount": 100 }, "agent": { "agent_id": "my-agent" } }'

Authorization

Submit an authorization request before your agent commits spend. SOXAgent evaluates it against active policies and returns a decision.

POST /v1/authorizations

Request Body

FieldTypeRequiredDescription
action.typestringYesAction type (e.g. refund_approve)
action.amountnumberNoMonetary amount (non-negative)
action.currencystringNoISO currency code (e.g. USD)
action.subtypestringNoAction subtype for granular matching
action.entitystringNoTarget entity identifier
action.business_unitstringNoBusiness unit for scope matching
action.jurisdictionstringNoJurisdiction for scope matching
agent.agent_idstringYesRegistered agent identifier
actors.requester_typestringNoType of requester (e.g. user, system, agent)
actors.requester_idstringNoID of the user/system requesting
actors.human_sponsor_idstringNoHuman sponsor for SoD checks
rationale_summarystringNoHuman-readable justification (max 2000 chars)
business_contextobjectNoOptional context: vendor, customer_id, order_id, reason_code
Example request (use sk_test_ for sandbox, sk_live_ for production)
curl -X POST https://soxagent-api.fly.dev/v1/authorizations \
  -H "Authorization: Bearer sk_live_abc123..." \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "action": {
      "type": "refund_approve",
      "amount": 150.00,
      "currency": "USD"
    },
    "agent": {
      "agent_id": "support-refund-agent"
    },
    "rationale_summary": "Customer refund for order #12345"
  }'

Response — Approved (201)

Approved response
{
  "request_id": "req_abc123",
  "status": "success",
  "data": {
    "id": "aut_7f3k9m2x",
    "state": "approved",
    "decision": "approved",
    "decision_mode": "auto",
    "action_type": "refund_approve",
    "amount": 150.00,
    "currency": "USD",
    "agent_id": "support-refund-agent",
    "risk_tier": "low",
    "risk_score": 12,
    "reason_codes": [],
    "winning_policy": {
      "policy_id": "pol_default",
      "version": 1
    },
    "decision_token": "dt_a1b2c3d4...",
    "timeout_at": null,
    "created_at": "2026-03-18T12:00:00.000Z",
    "agent_governance": {
      "governance_status": "registered",
      "control_tier": "standard",
      "environment": "production",
      "business_owner": "Jane Smith",
      "action_in_scope": true
    }
  }
}

Response — Escalated (202)

When the amount exceeds the auto-approve threshold, the request is escalated for human review.

Escalated response
{
  "request_id": "req_def456",
  "status": "success",
  "data": {
    "id": "aut_9k4m2n8p",
    "state": "pending_human_approval",
    "decision": "escalated",
    "decision_mode": "policy",
    "action_type": "refund_approve",
    "amount": 5000.00,
    "currency": "USD",
    "agent_id": "support-refund-agent",
    "risk_tier": "medium",
    "risk_score": 45,
    "reason_codes": ["amount_exceeds_threshold"],
    "winning_policy": {
      "policy_id": "pol_default",
      "version": 1
    },
    "decision_token": null,
    "approval_routing": {
      "approver_role": "finance_manager",
      "timeout_minutes": 1440,
      "timeout_disposition": "deny"
    },
    "approval_task": {
      "approval_id": "apr_x1y2z3",
      "approver_role": "finance_manager",
      "sla_due_at": "2026-03-19T12:00:00.000Z"
    },
    "timeout_at": "2026-03-19T12:00:00.000Z",
    "created_at": "2026-03-18T12:00:00.000Z"
  }
}

Response — Denied (403)

Denied response
{
  "request_id": "req_ghi789",
  "status": "error",
  "error": {
    "code": "POLICY_DENIED",
    "message": "Action denied by policy: prohibited action type"
  }
}

Decision Token

When a request is approved, the response includes a decision_token. This token is single-use and must be passed when reporting execution. It is not included in escalated or denied responses.

Execution Reporting

After executing the approved action, report the outcome back to SOXAgent. This closes the audit loop and enables reconciliation.

POST /v1/authorizations/:id/execution

Request body
{
  "decision_token": "dt_a1b2c3d4...",
  "execution_result": {
    "status": "succeeded",
    "executed_at": "2026-03-18T12:05:00.000Z",
    "amount": 150.00,
    "currency": "USD",
    "external_transaction_id": "txn_stripe_abc123"
  }
}
FieldTypeRequiredDescription
decision_tokenstringYesToken from the approved authorization
execution_result.statusstringYessucceeded or failed
execution_result.executed_atstringYesISO 8601 timestamp of execution
execution_result.amountnumberNoActual executed amount (for reconciliation)
execution_result.currencystringNo3-letter currency code
execution_result.external_transaction_idstringNoExternal system reference
execution_result.error_codestringNoError code when status is failed
execution_result.error_messagestringNoError description when status is failed
Response (200)
{
  "request_id": "req_jkl012",
  "status": "success",
  "data": {
    "authorization_id": "aut_7f3k9m2x",
    "state": "execution_confirmed",
    "execution": {
      "status": "succeeded",
      "external_transaction_id": "txn_stripe_abc123",
      "executed_at": "2026-03-18T12:05:00.000Z"
    },
    "reconciliation": {
      "status": "matched",
      "authorized_amount": 150.00,
      "executed_amount": 150.00,
      "variance": 0
    }
  }
}

Reconciliation compares the authorized amount and currency with the executed values. Status will be matched, mismatched, or failed.

Evidence Packs

Evidence packs are self-contained, cryptographically signed audit bundles for a single authorization. They contain everything an auditor needs to verify the decision chain.

GET /v1/authorizations/:id/evidence

Example request
curl https://soxagent-api.fly.dev/v1/authorizations/aut_7f3k9m2x/evidence \
  -H "Authorization: Bearer sk_live_abc123..."

The response is a comprehensive JSON document containing:

  • Authorization metadata — action, agent, decision, timestamps
  • Original request — the full submission payload
  • Policy snapshot — the exact policy version used for evaluation
  • Event chain — hash-chained sequence of all state transitions
  • Approval chain — human approvals with timestamps and roles
  • Execution & reconciliation — outcome and variance analysis
  • Risk assessment — score, tier, and factor decomposition
  • Compliance assessment — controls met, unmet, and review-required
  • Assertions — continuous assurance check results
  • SoD analysis — segregation of duties conflict check
  • Agent governance — registration status and control tier
  • Verification — integrity score and cryptographic signature

Each evidence pack includes a SHA-256 fingerprint for tamper detection and an Ed25519 digital signature. Public signing keys are available at GET /v1/evidence/public-key (no auth required).

Webhooks

Register webhook endpoints to receive real-time notifications when events occur.

Managing Webhooks

MethodEndpoint
POST/v1/webhooks
GET/v1/webhooks
GET/v1/webhooks/:id
PUT/v1/webhooks/:id
DELETE/v1/webhooks/:id

Event Types

  • authorization.decided
  • approval.requested
  • approval.recorded
  • execution.confirmed
  • execution.failed
  • reconciliation.completed
  • incident.opened

Signature Verification

Every webhook delivery includes a signature for verification:

  • X-SOXAgent-Signature — HMAC-SHA256 signature
  • X-SOXAgent-Timestamp — Unix timestamp of delivery
  • X-SOXAgent-Event — Event type
  • X-SOXAgent-Delivery-Id — Unique delivery identifier

Compute the expected signature as:

HMAC-SHA256(webhook_secret, "{timestamp}.{body}")

Webhooks have a 10-second timeout. Deliveries are fire-and-forget with no automatic retries.

Error Codes

All error responses use a consistent envelope:

{
  "request_id": "req_abc123",
  "status": "error",
  "error": {
    "code": "ERROR_CODE",
    "message": "Human-readable description",
    "details": {}
  }
}
HTTPCodeDescription
400INVALID_REQUESTMalformed or invalid request body
400MISSING_REQUIRED_FIELDA required field is missing
400IDEMPOTENCY_KEY_MISSINGPOST request missing Idempotency-Key header
400DECISION_TOKEN_INVALIDDecision token is invalid or expired
401UNAUTHORIZEDMissing or invalid authentication
403POLICY_DENIEDAction denied by policy evaluation
403BUDGET_EXCEEDEDAgent monthly budget limit reached
403AGENT_PAUSEDAgent is currently paused
403SOD_VIOLATIONSegregation of duties conflict detected
404NOT_FOUNDResource not found
409DECISION_TOKEN_REUSEDDecision token already consumed
409IDEMPOTENCY_CONFLICTSame key used with different request body
410TIMEOUT_EXPIREDApproval window has expired
429RATE_LIMIT_EXCEEDEDToo many requests
500INTERNAL_ERRORUnexpected server error

Code Examples

curl

Submit authorization (use sk_test_ for sandbox, sk_live_ for production)
# Use sk_test_ keys during development, sk_live_ keys in production
curl -X POST https://soxagent-api.fly.dev/v1/authorizations \
  -H "Authorization: Bearer $SOXAGENT_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "action": {
      "type": "refund_approve",
      "amount": 150.00,
      "currency": "USD"
    },
    "agent": {
      "agent_id": "support-refund-agent"
    }
  }'

Node.js

soxagent.js
const SOXAGENT_API = "https://soxagent-api.fly.dev";
// Use SOXAGENT_TEST_KEY (sk_test_...) in dev, SOXAGENT_API_KEY (sk_live_...) in prod
const API_KEY = process.env.SOXAGENT_API_KEY;

async function authorize(actionType, amount, currency, agentId) {
  const res = await fetch(`${SOXAGENT_API}/v1/authorizations`, {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${API_KEY}`,
      "Content-Type": "application/json",
      "Idempotency-Key": crypto.randomUUID(),
    },
    body: JSON.stringify({
      action: { type: actionType, amount, currency },
      agent: { agent_id: agentId },
    }),
  });

  const json = await res.json();

  if (json.status === "success") {
    const { decision, decision_token } = json.data;
    console.log(`Decision: ${decision}`);
    if (decision === "approved") {
      // Proceed with the action, then report execution
      return { approved: true, token: decision_token };
    }
    return { approved: false, decision };
  }

  throw new Error(json.error?.message || `API error: ${res.status}`);
}

// Usage
const result = await authorize("refund_approve", 150, "USD", "support-refund-agent");

Python

soxagent.py
import os
import uuid
import requests

SOXAGENT_API = "https://soxagent-api.fly.dev"
# Use SOXAGENT_TEST_KEY (sk_test_...) in dev, SOXAGENT_API_KEY (sk_live_...) in prod
API_KEY = os.environ["SOXAGENT_API_KEY"]

def authorize(action_type: str, amount: float, currency: str, agent_id: str):
    resp = requests.post(
        f"{SOXAGENT_API}/v1/authorizations",
        headers={
            "Authorization": f"Bearer {API_KEY}",
            "Content-Type": "application/json",
            "Idempotency-Key": str(uuid.uuid4()),
        },
        json={
            "action": {"type": action_type, "amount": amount, "currency": currency},
            "agent": {"agent_id": agent_id},
        },
    )
    resp.raise_for_status()
    data = resp.json()

    if data["status"] == "success":
        decision = data["data"]["decision"]
        token = data["data"].get("decision_token")
        print(f"Decision: {decision}")
        if decision == "approved":
            return {"approved": True, "token": token}
        return {"approved": False, "decision": decision}

    raise Exception(data.get("error", {}).get("message", f"API error: {resp.status_code}"))

# Usage
result = authorize("refund_approve", 150.00, "USD", "support-refund-agent")

What's Next

  • Dashboard — Monitor authorizations, agent health, risk scores, and compliance posture at app.soxagent.com
  • Policy engine — Configure multi-tier approval rules with spending thresholds, escalation routing, and timeout actions
  • Agent fleet governance — Register agents, assign owners, set budget limits, and define allowed action scopes
  • Compliance frameworks — Map controls to SOX 404 control objectives with coverage gap detection
  • Continuous assurance — Automated assertion checks, risk scoring, and maturity assessments

FAQ

What is SOXAgent?

SOXAgent is a financial governance layer for AI agents. Before an agent refunds, pays, approves, or commits spend, SOXAgent evaluates policy, checks approvals and SoD rules, records evidence, and supports ongoing control monitoring.

What's the difference between TEST and LIVE?

TEST is a sandbox for validating policies, approvals, evidence, SoD behavior, and control monitoring. LIVE is for production governance. They are isolated environments inside the same organization.

What's the difference between sk_test_ and sk_live_ keys?

sk_test_ keys work only in TEST. sk_live_ keys work only in LIVE. Use TEST for sandbox validation and LIVE for production traffic.

Does TEST stay isolated from LIVE?

Yes. TEST and LIVE are environment-isolated. Requests, policies, evidence, dashboard data, and runtime policy evaluation stay separate across the two environments.

What happens when a request matches multiple policies?

SOXAgent resolves overlap automatically. The most restrictive result wins first, then more specific rules win over broader ones, with deterministic tiebreaking when needed.

Does SOXAgent support segregation of duties?

Yes. SOXAgent supports SoD role assignments, conflict detection, approval-time blocking, and evidence output for SoD-relevant actions.

What evidence does SOXAgent generate?

Policy snapshots, event history, approvals, decision reasoning, integrity checks, and exportable evidence packs tied to a request lifecycle.

How does SOXAgent help with SOX 404?

SOXAgent is currently SOX 404-first. It helps teams enforce, evidence, and monitor financial-control workflows focused on authorization controls, segregation of duties, and evidence preservation for AI-driven financial actions.

Do humans create transactions in the dashboard?

SOXAgent is primarily a control plane where systems and agents submit requests. Humans configure controls, review approvals, monitor controls, inspect evidence, and investigate outcomes.

Does SOXAgent replace my ERP or finance system?

No. SOXAgent sits in front of important actions and governs whether those actions should proceed and what evidence should be captured. It does not replace your financial system of record.