Developer Guide
Add AI governance to any application with ARQERA's API. This guide covers authentication, the core API, SDKs, and common patterns.
Quick Start
1. Get an API Key
- Log in to arqera.io
- Go to Settings → API Keys
- Click Create Key
- Copy the key (starts with
ak_)
2. Make Your First Call
curl -X POST https://api.arqera.io/v1/governance/evaluate \
-H "Authorization: Bearer ak_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"action": "send_email",
"context": {
"to": "john@example.com",
"subject": "Meeting follow-up"
}
}'
Response:
{
"verdict": "PROCEED",
"evidence_id": "ev_abc123",
"reasoning": "Action matches policy: routine communications allowed",
"evaluated_at": "2026-04-13T10:30:00Z",
"duration_ms": 12
}
3. Act on the Verdict
const response = await fetch('https://api.arqera.io/v1/governance/evaluate', {
method: 'POST',
headers: {
'Authorization': 'Bearer ak_your_api_key',
'Content-Type': 'application/json'
},
body: JSON.stringify({
action: 'send_email',
context: { to: 'john@example.com', subject: 'Meeting follow-up' }
})
});
const { verdict, evidence_id } = await response.json();
if (verdict === 'PROCEED') {
// Execute the action
await sendEmail(to, subject, body);
} else if (verdict === 'ESCALATE') {
// Route to human approval
await createApprovalRequest(evidence_id);
} else if (verdict === 'BLOCK') {
// Stop and log
console.log('Action blocked by governance');
}
Core Concepts
Actions
An action is anything your AI wants to do:
| Action Type | Examples |
|---|---|
send_email | Send an email |
read_file | Access a document |
create_record | Add to database |
call_api | External API call |
spend_money | Purchase, payment |
Context
Context is the details of the action. The more context, the better the evaluation:
{
"action": "send_email",
"context": {
"to": "john@example.com",
"cc": ["team@company.com"],
"subject": "Q4 Contract Discussion",
"body_preview": "I'd like to discuss the terms...",
"has_attachments": true,
"attachment_types": ["pdf"],
"sender_role": "sales_rep",
"recipient_type": "external"
}
}
Verdicts
| Verdict | What to do | HTTP Status |
|---|---|---|
PROCEED | Execute the action | 200 |
ESCALATE | Queue for human approval | 200 |
BLOCK | Do not execute | 200 |
Note: All verdicts return 200. The verdict itself tells you what to do.
Evidence
Every evaluation creates an evidence record. This is your audit trail:
{
"evidence_id": "ev_abc123",
"action": "send_email",
"verdict": "PROCEED",
"reasoning": "Policy: routine-comms matched. All laws passed.",
"laws_evaluated": [
{"law": "safety_dominance", "passed": true},
{"law": "budget_conservation", "passed": true},
{"law": "bounded_autonomy", "passed": true}
],
"timestamp": "2026-04-13T10:30:00Z",
"signature": "sha256:abc123..."
}
API Reference
POST /v1/governance/evaluate
Evaluate an action against governance policies.
Request:
{
"action": "string (required)",
"context": "object (required)",
"agent_id": "string (optional)",
"user_id": "string (optional)",
"tenant_id": "string (optional)",
"idempotency_key": "string (optional)"
}
Response:
{
"verdict": "PROCEED | ESCALATE | BLOCK",
"evidence_id": "string",
"reasoning": "string",
"evaluated_at": "ISO 8601 timestamp",
"duration_ms": "number",
"escalation_id": "string (if ESCALATE)",
"block_reason": "string (if BLOCK)"
}
POST /v1/evidence
Submit evidence for an action that bypassed real-time evaluation.
Request:
{
"action": "string",
"context": "object",
"outcome": "success | failure",
"executed_at": "ISO 8601 timestamp"
}
GET /v1/evidence/{evidence_id}
Retrieve a specific evidence record.
GET /v1/evidence
List evidence records with filters.
Query params:
from— Start timestampto— End timestampaction— Filter by action typeverdict— Filter by verdictlimit— Max results (default 100)cursor— Pagination cursor
POST /v1/approvals/{approval_id}/approve
Approve an escalated action.
POST /v1/approvals/{approval_id}/reject
Reject an escalated action.
GET /v1/approvals
List pending approvals.
SDKs
Python
pip install arqera
from arqera import ArqeraClient
client = ArqeraClient(api_key="ak_your_api_key")
# Evaluate an action
result = client.evaluate(
action="send_email",
context={
"to": "john@example.com",
"subject": "Meeting follow-up"
}
)
if result.verdict == "PROCEED":
# Execute
pass
elif result.verdict == "ESCALATE":
# Queue for approval
approval_id = result.escalation_id
Full Python SDK documentation →
TypeScript
npm install @arqera/sdk
import { ArqeraClient } from '@arqera/sdk';
const client = new ArqeraClient({ apiKey: 'ak_your_api_key' });
const result = await client.evaluate({
action: 'send_email',
context: {
to: 'john@example.com',
subject: 'Meeting follow-up'
}
});
if (result.verdict === 'PROCEED') {
// Execute
} else if (result.verdict === 'ESCALATE') {
// Queue for approval
}
Full TypeScript SDK documentation →
Common Patterns
Governed Agent
Wrap your AI agent to evaluate every action:
class GovernedAgent:
def __init__(self, arqera_client, agent):
self.governance = arqera_client
self.agent = agent
async def execute(self, action, context):
# Evaluate first
result = await self.governance.evaluate(action, context)
if result.verdict == "PROCEED":
return await self.agent.execute(action, context)
elif result.verdict == "ESCALATE":
return {"status": "pending_approval", "id": result.escalation_id}
else:
return {"status": "blocked", "reason": result.block_reason}
Governed Chatbot
Add governance to LLM function calls:
async def handle_function_call(function_name, arguments):
# Evaluate the function call
result = await arqera.evaluate(
action=f"function_call:{function_name}",
context=arguments
)
if result.verdict == "PROCEED":
return await execute_function(function_name, arguments)
elif result.verdict == "ESCALATE":
return f"This action needs approval. Reference: {result.escalation_id}"
else:
return f"I can't do that. Reason: {result.block_reason}"
Batch Evaluation
Evaluate multiple actions at once:
results = await client.evaluate_batch([
{"action": "send_email", "context": {...}},
{"action": "read_file", "context": {...}},
{"action": "create_record", "context": {...}}
])
for result in results:
print(f"{result.action}: {result.verdict}")
Async Evidence
For high-throughput scenarios, submit evidence asynchronously:
# Execute first, submit evidence after
await execute_action(action, context)
# Submit evidence (non-blocking)
await client.submit_evidence(
action=action,
context=context,
outcome="success"
)
Webhooks
Get notified when things happen:
# In your webhook handler
@app.post("/webhooks/arqera")
async def handle_webhook(request):
event = request.json()
if event["type"] == "approval.created":
# Notify the right person
await notify_approver(event["data"]["approval_id"])
elif event["type"] == "approval.resolved":
# Continue the workflow
if event["data"]["resolution"] == "approved":
await resume_action(event["data"]["evidence_id"])
Configure webhooks at Settings → Webhooks in the dashboard.
Rate Limits
| Plan | Evaluations/second | Evidence records/day |
|---|---|---|
| Free | 10 | 10,000 |
| Personal | 50 | 100,000 |
| Pro | 100 | Unlimited |
| Team | 200 | Unlimited |
| Enterprise | Custom | Unlimited |
Rate limit headers:
X-RateLimit-Limit— Your limitX-RateLimit-Remaining— Remaining callsX-RateLimit-Reset— Reset timestamp
Error Handling
try:
result = await client.evaluate(action, context)
except ArqeraAuthError:
# Invalid API key
except ArqeraRateLimitError as e:
# Wait and retry
await asyncio.sleep(e.retry_after)
except ArqeraServerError:
# Temporary issue, retry with backoff
HTTP status codes:
| Code | Meaning |
|---|---|
| 200 | Success (check verdict) |
| 400 | Bad request (invalid input) |
| 401 | Unauthorized (bad API key) |
| 429 | Rate limited |
| 500 | Server error |
Testing
Sandbox Mode
Use the sandbox for testing without affecting production data:
curl -X POST https://sandbox.api.arqera.io/v1/governance/evaluate \
-H "Authorization: Bearer ak_sandbox_your_key" \
...
Test Policies
Create test policies in the dashboard under Governance → Test Policies.
Mock Responses
The SDK supports mock mode:
client = ArqeraClient(api_key="ak_test", mock=True)
client.set_mock_verdict("PROCEED") # All evaluations return PROCEED
Security
- API keys are tenant-scoped. One key per environment.
- TLS 1.3 for all connections
- Evidence is signed with SHA-256
- Audit logs are immutable
Rotate keys regularly: Settings → API Keys → Rotate.
Next Steps
Questions? developers@arqera.io