Developer Docs

REST API Reference

The AiT Hosted Agents API is a JSON-over-HTTPS REST API deployed on Google Cloud Run. All endpoints are versioned under /api/v1/ and follow consistent error response conventions.

Base URLhttps://api.intelligentit.io

Interactive playground coming soon. Until then, use curl or Postman with your API token from the dashboard. All requests require a Content-Type: application/json header.

Authentication

All endpoints require a Clerk JWT passed in the Authorization header. Tokens are scoped to the authenticated user and their active organization (org_id claim). Requests without a valid token or without an active org session receive a 401 or 403 respectively.

Obtaining a token

Use getToken() from @clerk/nextjs/client in your frontend, or the Clerk Backend SDK for server-to-server requests.

// Frontend (React / Next.js)
import { useAuth } from '@clerk/nextjs';

const { getToken } = useAuth();
const token = await getToken();

const res = await fetch('https://api.intelligentit.io/api/v1/agent/run', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${token}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ agentId: 'helpdesk-tier1-triage', message: '...' }),
});

Using curl

# Replace <YOUR_TOKEN> with the JWT from your dashboard or getToken()
curl -X POST https://api.intelligentit.io/api/v1/agent/run \
  -H "Authorization: Bearer <YOUR_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"agentId":"helpdesk-tier1-triage","message":"Router offline at floor 3"}'

Error codes

CodeHTTPMeaning
UNAUTHENTICATED401Missing or expired token
NO_ORG403Token valid but no active organization session
INSUFFICIENT_PERMISSIONS403Org:admin role required for this action
VALIDATION_ERROR400Request body failed Zod validation
TENANT_NOT_FOUND404Organization not yet onboarded
BAA_REQUIRED403Healthcare/BehavioralHealth vertical requires a signed BAA
DLP_INPUT_BLOCKED422PHI detected in input — remove before submitting

Agent Runs

Execute AI agents and retrieve run history. All runs are compliance-audited: only SHA-256 hashes of input/output are persisted — plaintext is never stored.

POST/api/v1/agent/run
Auth required

Execute an agent template against a user message. The response includes the model output, an audit ID for the immutable audit log entry, DLP policy flags, and token usage. For healthcare/behavioral-health verticals a signed BAA must be on file; input containing PHI is blocked at the DLP layer and never forwarded to the model.

Request body

{
  "agentId": "helpdesk-tier1-triage",
  "message": "Router at floor 3 is offline since 09:00 — ticket ITSD-4421",
  "systemPromptOverride": "(optional) Custom system prompt for advanced integrations."
}

// agentId — string (1–100 chars). Built-in templates:
//   "coleman-clinical-docs"       — Clinical documentation (Healthcare)
//   "helpdesk-tier1-triage"       — IT helpdesk triage + priority classification
//   "compliance-evidence-collector" — SOC 2 / HIPAA / ISO 27001 evidence gathering
//   "audit-trail-narrator"        — Plain-language audit-log summaries

// message — string (1–32 000 chars). Never stored; only SHA-256 is written to the audit log.
// systemPromptOverride — string (max 8 000 chars). Overrides the template default prompt.

Response

// HTTP 200
{
  "response": "P2 — Network / Infrastructure. Recommended path: on-site check of patch panel ...",
  "audit_id": "aud_01JQABCDE12345XYZ",
  "policy_flags": [],
  "model_used": "claude-haiku-3-5",
  "tokens_used": 312
}

// HTTP 422 — PHI detected
{
  "error": "Input blocked: protected health information (PHI) detected. Please remove PHI before submitting.",
  "code": "DLP_INPUT_BLOCKED",
  "policy_flags": [
    { "type": "PERSON_NAME", "offset": 12, "length": 9 },
    { "type": "DATE_OF_BIRTH", "offset": 34, "length": 10 }
  ]
}
GET/api/v1/runs
Auth required

List agent runs for the authenticated organization. Results are paginated, newest first. Only metadata fields are returned (audit IDs, model used, token counts, policy flags) — plaintext input/output is never stored and cannot be retrieved.

Planned — available in Wave 24. Returns stub data until deployed.

Response

// HTTP 200
{
  "runs": [
    {
      "id": "aud_01JQABCDE12345XYZ",
      "agent_id": "helpdesk-tier1-triage",
      "user_id": "user_2abc...",
      "action": "agent_run",
      "model_used": "claude-haiku-3-5",
      "tokens_used": 312,
      "latency_ms": 1840,
      "policy_flags": [],
      "created_at": "2026-05-12T14:22:00Z"
    }
  ],
  "total": 1,
  "page": 1,
  "per_page": 25
}

// Query params (all optional):
//   ?page=1         — page number (default: 1)
//   ?per_page=25    — results per page (max: 100)
//   ?agent_id=...   — filter by agent template ID
GET/api/v1/runs/:runId
Auth required

Retrieve metadata for a single run by its audit ID. Returns the same fields as the list endpoint plus the hash-chain fields for audit chain verification.

Planned — available in Wave 24.

Response

// HTTP 200
{
  "run": {
    "id": "aud_01JQABCDE12345XYZ",
    "agent_id": "helpdesk-tier1-triage",
    "user_id": "user_2abc...",
    "action": "agent_run",
    "model_used": "claude-haiku-3-5",
    "tokens_used": 312,
    "latency_ms": 1840,
    "input_hash": "e3b0c44298fc1c149afbf4c8996fb924...",
    "output_hash": "a87ff679a2f3e71d9181a67b7542122c...",
    "policy_flags": [],
    "created_at": "2026-05-12T14:22:00Z",
    "chain": {
      "prev_hash": "000000000000000000000000000000000000000000000000000000000000",
      "row_hash": "8c7dd922ad47494fc02c388e12c00eac..."
    }
  }
}

// HTTP 404
{ "error": "Run not found", "code": "NOT_FOUND" }

Stats

Aggregate usage metrics scoped to the authenticated organization.

GET/api/v1/stats
Auth required

Returns tenant-level usage statistics for the current billing period: run counts, token totals, plan limits, and per-agent breakdowns.

Planned — available in Wave 25. Current usage data is available in the dashboard under Settings → Usage.

Response

// HTTP 200
{
  "tenant_id": "ten_01JQABCDE12345",
  "period": {
    "start": "2026-05-01T00:00:00Z",
    "end":   "2026-05-31T23:59:59Z"
  },
  "runs_total": 842,
  "runs_remaining": 158,
  "tokens_total": 284920,
  "plan": "pro",
  "plan_run_limit": 1000,
  "by_agent": {
    "helpdesk-tier1-triage": { "runs": 600, "tokens": 192000 },
    "compliance-evidence-collector": { "runs": 242, "tokens": 92920 }
  }
}

// HTTP 404
{ "error": "Organization not found.", "code": "TENANT_NOT_FOUND" }

Provisioning

Manage LiteLLM virtual key provisioning for your organization. Provisioning is required before executing agents — it allocates a rate-limited gateway key scoped to your plan's token budget. All provisioning mutations require the org:admin role.

POST/api/v1/provision/tenant
Admin onlyAuth required

Issue a LiteLLM virtual key for the organization. Idempotent — if already provisioned, returns the existing key ID without re-issuing. The raw key value is handled in-memory only and is never persisted or returned in any response.

Request body

{
  "orgId": "org_2abc...",   // Must match the org_id in your JWT
  "plan": "pro"             // "pilot" | "starter" | "pro" | "enterprise"
}

Response

// HTTP 200 — newly provisioned
{
  "success": true,
  "keyId": "vk_01JQABCDE12345"
}

// HTTP 200 — already provisioned (idempotent)
{
  "success": true,
  "keyId": "vk_01JQABCDE12345",
  "message": "Tenant already provisioned. Use DELETE to re-provision."
}

// HTTP 403 — org mismatch
{
  "error": "orgId in request does not match authenticated organization",
  "code": "ORG_MISMATCH"
}
GET/api/v1/provision/tenant/status
Auth required

Read the provisioning state and remaining token budget for the caller's organization. The key ID (a safe gateway alias) is returned — the raw key value is never accessible after issuance.

Response

// HTTP 200 — provisioned
{
  "provisioned": true,
  "plan": "pro",
  "keyId": "vk_01JQABCDE12345",
  "budgetUsd": 48.20
}

// HTTP 200 — not yet provisioned
{
  "provisioned": false,
  "plan": "free",
  "keyId": null,
  "budgetUsd": null
}
DELETE/api/v1/provision/tenant
Admin onlyAuth required

Revoke the organization's virtual key and clear the provisioning record. Use this to re-provision (e.g. after a plan change) or to offboard. Idempotent — returns success if the tenant was not provisioned.

Response

// HTTP 200
{ "success": true }

// HTTP 200 — was not provisioned
{ "success": true, "message": "Tenant was not provisioned." }

// HTTP 502 — gateway revocation failed
{
  "error": "Failed to revoke virtual key. Please try again.",
  "code": "KEY_REVOCATION_FAILED"
}

Log Sources

Register external log sources for the Audit-Trail Narrator agent. Supported source types: m365_unified_audit, google_workspace_admin, gcp_cloud_audit, splunk_hec, azure_sentinel, custom_webhook. Config stores only non-secret connection parameters. Credentials live in Google Secret Manager and are referenced by a secretRef name.

GET/api/v1/log-sources
Auth required

List all log-source registrations for the authenticated organization. Credential values are never returned — only the secretRef alias is included.

Response

// HTTP 200
{
  "sources": [
    {
      "id": "ls_01JQABCDE12345",
      "org_id": "org_2abc...",
      "source_type": "m365_unified_audit",
      "display_name": "Contoso M365 Audit",
      "config": { "tenantId": "contoso.onmicrosoft.com" },
      "secret_ref": "m365__contoso__audit-secret",
      "enabled": true,
      "last_fetched_at": "2026-05-12T13:00:00Z",
      "fetch_error": null,
      "created_at": "2026-04-01T10:00:00Z",
      "updated_at": "2026-05-12T13:00:00Z"
    }
  ]
}
POST/api/v1/log-sources
Auth required

Register a new log source for the organization. Config fields are validated per source type. Credentials are not accepted here — manage them in GSM and provide the secret name as secretRef.

Request body

{
  "sourceType": "m365_unified_audit",
  "displayName": "Contoso M365 Audit",
  "config": {
    "tenantId": "contoso.onmicrosoft.com"
  },
  "secretRef": "m365__contoso__audit-secret"  // Optional GSM secret name
}

// Per-type required config fields:
//   m365_unified_audit        → { tenantId }
//   google_workspace_admin    → { customerId }
//   gcp_cloud_audit           → { projectId }
//   splunk_hec                → { endpoint }
//   azure_sentinel            → { workspaceId }
//   custom_webhook            → {} (no required fields)

Response

// HTTP 201
{
  "source": {
    "id": "ls_01JQABCDE12345",
    "org_id": "org_2abc...",
    "source_type": "m365_unified_audit",
    "display_name": "Contoso M365 Audit",
    "config": { "tenantId": "contoso.onmicrosoft.com" },
    "secret_ref": "m365__contoso__audit-secret",
    "enabled": true,
    "created_at": "2026-05-12T14:00:00Z",
    "updated_at": "2026-05-12T14:00:00Z"
  }
}
PATCH/api/v1/log-sources/:id
Auth required

Update displayName, config, and/or the enabled flag for a registered source. At least one field must be provided. Org ownership is verified before any mutation — cross-tenant updates are rejected.

Request body

// All fields optional — at least one required
{
  "displayName": "Contoso M365 Audit (Production)",
  "config": { "tenantId": "contoso.onmicrosoft.com" },
  "enabled": false
}

Response

// HTTP 200
{
  "source": {
    "id": "ls_01JQABCDE12345",
    "display_name": "Contoso M365 Audit (Production)",
    "enabled": false,
    "updated_at": "2026-05-12T15:00:00Z"
    // ... all other fields unchanged
  }
}

// HTTP 404
{ "error": "Log source not found", "code": "NOT_FOUND" }
DELETE/api/v1/log-sources/:id
Auth required

Remove a log source registration. Org ownership is verified before deletion. This does not revoke the GSM secret referenced by secretRef — manage that separately.

Response

// HTTP 200
{ "ok": true }

// HTTP 404
{ "error": "Log source not found", "code": "NOT_FOUND" }

// HTTP 403
{ "error": "Forbidden", "code": "FORBIDDEN" }

Billing

Subscription and plan information powered by Stripe. All billing mutations happen via the Stripe Customer Portal — this API surface is read-only for subscription state.

GET/api/v1/billing/subscription
Auth required

Retrieve the current Stripe subscription state for the authenticated organization, including plan, status, renewal date, and Stripe customer ID.

Planned — available in Wave 26. Current billing is managed in the dashboard under Settings → Billing.

Response

// HTTP 200 — active subscription
{
  "customer_id": "cus_Pxxx...",
  "subscription_id": "sub_1Pxxx...",
  "plan": "pro",
  "status": "active",
  "current_period_end": "2026-06-12T00:00:00Z",
  "cancel_at_period_end": false,
  "features": {
    "run_limit": 1000,
    "agents_included": ["helpdesk-tier1-triage", "compliance-evidence-collector"],
    "baa_available": false
  }
}

// HTTP 200 — no active subscription
{
  "customer_id": null,
  "subscription_id": null,
  "plan": "free",
  "status": "none"
}

Webhooks

Stripe sends signed POST requests to this endpoint on billing events. The signature is validated with your Stripe webhook secret before any state is mutated. This endpoint is internal — do not call it directly.

POST/api/v1/billing/webhook
InternalPublic

Receives Stripe webhook events (checkout.session.completed, customer.subscription.updated, customer.subscription.deleted, invoice.payment_failed). The Stripe-Signature header is verified using HMAC-SHA256 before processing. Returns 200 immediately for all valid signatures to prevent Stripe retries.

Configure your Stripe webhook to point to https://api.intelligentit.io/api/v1/billing/webhook and forward the raw request body. Set the webhook secret in GSM as stripe__hosted-agents__webhook-secret.

Request body

// Stripe sends standard webhook event envelopes.
// The raw body (not parsed JSON) must be forwarded for signature verification.
//
// Handled event types:
//   checkout.session.completed       — activate subscription, provision tenant
//   customer.subscription.updated    — sync plan changes to DB
//   customer.subscription.deleted    — downgrade to free tier
//   invoice.payment_failed           — flag subscription as past_due

{
  "id": "evt_1Pxxx...",
  "type": "checkout.session.completed",
  "data": {
    "object": {
      "id": "cs_1Pxxx...",
      "customer": "cus_Pxxx...",
      "subscription": "sub_1Pxxx...",
      "metadata": { "org_id": "org_2abc..." }
    }
  }
}

Response

// HTTP 200 — signature valid, event queued
{ "received": true }

// HTTP 400 — signature invalid or missing
{ "error": "Invalid Stripe signature", "code": "WEBHOOK_SIGNATURE_INVALID" }

Need help integrating?

Book a technical onboarding session with our team.

Schedule onboarding