Developer Documentation
A REST API and webhooks system designed for engineering teams who want findings in their own tooling. Integrate with any ticketing system, SIEM, or workflow tool. The customer's developers stay in control.
TITAN AI does not write tickets into customer ticketing systems. There are too many of them, with too many compliance variants, and direct ticket writes create liability for both vendor and customer. Instead, TITAN AI exposes findings via a REST API and emits events to customer-registered webhook endpoints. The customer's engineering team writes a small adapter that translates TITAN AI findings into whatever ticketing, SIEM, or workflow system the customer already runs.
This is the same model used by every mature security vendor in the category. It is the model that scales across hundreds of customers with different toolchains, and it is the model that procurement teams expect when reviewing a security platform.
Sign up for a trial or contact sales. License keys are provisioned per tenant and scope all API access.
Make a GET request to /api/v1/findings with your license key. Findings return as JSON.
POST your callback URL to /api/v1/webhooks. TITAN AI will fire events when finding state changes.
Map TITAN AI findings to your ticket system, SIEM, or workflow tool. The customer's engineering team owns this layer.
All API requests require a license key in the X-License-Key header. The same license key authorizes both REST API calls and webhook deliveries.
curl https://api.titanaisec.com/api/v1/findings \
-H "X-License-Key: ttl_yourlicensekeyhere"
The Findings API exposes the current state of all findings across the customer's connected Azure subscriptions.
Returns all current findings for the tenant. Findings are scoped by license key.
| Parameter | Type | Description |
|---|---|---|
severity | string | Filter by severity. One of critical, high, medium, low, info |
category | string | Filter by layer. Example: network, identity, storage, keyvault, compliance, cost |
subscription_id | string | Filter to a single Azure subscription |
since | ISO 8601 timestamp | Return only findings detected or updated after this time |
limit | integer | Max results per page. Default 100, max 500 |
curl "https://api.titanaisec.com/api/v1/findings?severity=critical&limit=10" \
-H "X-License-Key: ttl_yourlicensekeyhere"
{
"findings": [
{
"id": "azure-nsg-prod-vnet-rule1-abc123",
"title": "NSG allows SSH/RDP from internet",
"severity": "critical",
"category": "network",
"layer": "infrastructure",
"subscription_id": "f623a36c-87b5-48e4-a3d4-1c6dc182eb43",
"environment": "PROD",
"resource_id": "/subscriptions/.../networkSecurityGroups/nsg-prod-web",
"framework": "NIST 800-53 SC-7, CIS Azure 6.1",
"description": "NSG rule allows inbound from 0.0.0.0/0 to port 22.",
"recommendation": "Restrict source to corporate IPs or use Azure Bastion.",
"detected_at": "2026-05-15T18:42:11Z",
"state": "open"
}
],
"total": 47,
"has_more": false
}
Returns a single finding with full detail including resource metadata and remediation guidance.
Returns the full audit trail for a finding: every state change, acceptance, resolution, and remediation request, with timestamps and user attribution.
{
"finding_id": "azure-nsg-prod-vnet-rule1-abc123",
"history": [
{ "action": "detected", "timestamp": "2026-05-10T12:00:00Z", "by": "scanner" },
{ "action": "accept_risk", "timestamp": "2026-05-11T09:15:22Z", "by": "[email protected]", "justification": "Approved exception, ticket #4521", "expires_at": "2026-08-11T00:00:00Z" },
{ "action": "expired", "timestamp": "2026-08-11T00:00:01Z", "by": "system" },
{ "action": "redetected", "timestamp": "2026-08-11T00:05:00Z", "by": "scanner" }
]
}
Three customer-controlled actions can be taken on any finding: accept risk, mark resolved, or request remediation. Every action is logged to the finding's history.
Accept the risk for this finding. The finding is hidden from default views until expiry or until the underlying issue changes. Requires a justification string. Optional expiry.
{
"justification": "Compensating control X in place. Approved by security council 2026-05-14.",
"expires_at": "2026-08-14T00:00:00Z",
"user": "[email protected]"
}
Mark a finding as resolved. The next scan will re-check the underlying resource. If the issue is still present, the finding is automatically reopened.
{
"user": "[email protected]",
"evidence": "PR #4521 merged, NSG rule removed."
}
Request that TITAN AI auto-remediate a low or medium severity finding. Auto-remediation is disabled by default and must be explicitly enabled per tenant. Critical severity findings cannot be auto-remediated under any circumstances.
{
"user": "[email protected]",
"approval_required": true
}
Instead of polling the Findings API, register a webhook URL and TITAN AI will fire events to it whenever a finding is detected, changes state, or is acted upon. This is the recommended pattern for production integrations.
Register a new webhook endpoint. TITAN AI will send signed POST requests to this URL on finding events.
{
"url": "https://your-app.example.com/titan-webhook",
"events": ["finding.detected", "finding.resolved", "finding.accepted"],
"secret": "your-shared-secret-for-signature-verification"
}
{
"webhook_id": "wh_abc123def456",
"url": "https://your-app.example.com/titan-webhook",
"events": ["finding.detected", "finding.resolved", "finding.accepted"],
"created_at": "2026-05-15T19:00:00Z"
}
List all registered webhooks for the tenant.
Unregister a webhook. No more events will be delivered to this URL.
Every webhook delivery includes an X-Titan-Signature header containing an HMAC-SHA256 signature of the request body. Compute the signature using the shared secret provided at registration time and compare. Reject any request whose signature does not match.
# Python example
import hmac, hashlib
def verify_webhook(body_bytes, signature_header, shared_secret):
expected = hmac.new(
shared_secret.encode(),
body_bytes,
hashlib.sha256
).hexdigest()
return hmac.compare_digest(expected, signature_header)
| Event | Fires when |
|---|---|
finding.detected | A new finding is discovered by any scanner |
finding.updated | An existing finding's details change (severity rescored, description updated) |
finding.resolved | A finding is marked resolved or auto-confirmed resolved by a rescan |
finding.accepted | Risk has been accepted for a finding |
finding.expired | An accepted-risk exception has reached its expiry timestamp |
finding.remediated | Auto-remediation has been successfully applied |
scan.completed | A full scan cycle has completed across all subscriptions |
TITAN AI can apply remediations on the customer's behalf for low and medium severity findings, but only when the customer has explicitly opted in.
allow_auto_remediate: true in tenant settings. Even with auto-remediation enabled, critical severity findings will never be auto-fixed. Remediation requires the customer's Service Principal to have appropriate write permissions (typically Contributor on the affected resource).
POST /api/v1/findings/{id}/remediate.finding.remediated webhook event fires on success, or finding.remediation_failed on error.Auto-remediation is currently supported for the following finding categories, all at low or medium severity:
All webhook events follow a consistent envelope structure:
{
"event_id": "evt_01H7XYZ...",
"event_type": "finding.detected",
"tenant_id": "tnt_abc123",
"timestamp": "2026-05-15T19:42:11Z",
"data": {
"finding": {
"id": "azure-storage-prod-stacct1-http",
"title": "Storage account allows insecure HTTP",
"severity": "high",
"category": "storage",
"subscription_id": "f623a36c-...",
"environment": "PROD",
"resource_id": "/subscriptions/.../storageAccounts/stacct1",
"framework": "CIS Azure 3.1, PCI DSS 4.1",
"description": "Data in transit can be intercepted.",
"recommendation": "Enable secure transfer required.",
"detected_at": "2026-05-15T19:42:11Z",
"state": "open"
}
}
}
The API uses standard HTTP status codes. Error responses are JSON with a consistent shape:
{
"error": {
"code": "invalid_license_key",
"message": "The provided license key is invalid or has been revoked.",
"request_id": "req_01H7XYZ..."
}
}
| Status | Code | Meaning |
|---|---|---|
| 400 | invalid_request | Required parameter missing or malformed |
| 401 | invalid_license_key | License key missing, malformed, or revoked |
| 403 | auto_remediate_disabled | Tenant has not enabled auto-remediation |
| 403 | critical_remediation_blocked | Cannot auto-remediate critical severity findings |
| 404 | finding_not_found | The finding ID does not exist or is not visible to this tenant |
| 429 | rate_limited | Too many requests. Back off and retry after the time given in the Retry-After header |
| 500 | internal_error | Unexpected error. Include the request_id when contacting support |
API requests are rate limited per license key:
| Endpoint group | Limit |
|---|---|
Read endpoints (GET /findings, GET /findings/*) | 120 requests per minute |
Write endpoints (POST, DELETE) | 30 requests per minute |
| Webhook deliveries (outbound from TITAN AI to your endpoint) | No customer-side limit; TITAN AI retries up to 5 times with exponential backoff on 5xx or timeout |
Customers running into rate limits at scale should contact support to discuss higher tier limits.
[email protected] with the question and your tenant ID. Founding customers have direct engineering team access.