Integration guide
Deploying the team
Every deployment gets two keys from the owner. A public key for the browser agent — locked to the client’s registered domains — and a secret server key for sensitive events like logins, transfers and data exports. Events are rejected until the owner activates the deployment.
1 · Websites: add the browser agent
Paste before </body>. It reports page views and scans form submissions for injection attacks and exposed card/ID numbers. Form contents are inspected on our side and immediately discarded.
<script src="https://your-team.netlify.app/agent.js" data-key="ast_pub_…" defer></script>Report login outcomes from the page too, if your login happens client-side:
AISecurityTeam.track('auth.login_failed', { actorId: 'user@example.com' })2 · Servers: send events to the API
Call from your backend whenever something security-relevant happens. Batch up to 100 events per request. Keep the secret key on the server only.
curl -X POST https://your-team.netlify.app/api/v1/events \
-H "Authorization: Bearer ast_sec_…" \
-H "Content-Type: application/json" \
-d '{"type":"payment.transfer","actorId":"user_42","amount":2500,"target":"payee_981","ip":"203.0.113.7"}'await fetch('https://your-team.netlify.app/api/v1/events', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.AI_SECURITY_TEAM_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
events: [
{ type: 'auth.login_failed', actorId: user.id, ip: req.ip },
{ type: 'http.request', ip: req.ip, path: req.originalUrl, userAgent: req.get('user-agent') },
],
}),
})Event reference
| type | useful fields | who watches |
|---|---|---|
| auth.login_failed | actorId, ip | Sentinel: brute force, credential stuffing |
| auth.login_success | actorId, ip, country, deviceId | Watchtower: new-country and new-device logins |
| auth.password_reset | actorId, ip | Sentinel + Ledger: account-takeover signals |
| account.security_change | actorId, change | Sentinel: MFA, email, phone, recovery changes |
| account.privilege_change | actorId, newRole | Sentinel: privilege escalation |
| payment.payee_added | actorId, target | Ledger: fresh-payee fraud |
| payment.transfer | actorId, amount, target | Ledger: thresholds, velocity, anomalies |
| data.export | actorId, records, target | Vault: bulk exports |
| data.access | actorId, target | Vault: scraping |
| http.request | ip, path, userAgent | Watchtower: floods, probes, attack tools |
| input.submitted | payload, path | Sentinel + Vault: injection & PII (payload is never stored) |
| page_view | path | Watchtower: request floods (browser agent) |
All fields are optional except type. Common fields: actorId, ip, country (ISO code), userAgent, amount, target, records, path, payload. Send sessionId and deviceId so the Investigator can link one person's activity across agents. change is one of mfa_disabled, mfa_enabled, email_changed, phone_changed, password_changed, recovery_changed, api_key_created. Server events may set occurredAt (ISO time, up to 30 days old) to backfill history.
3 · Alerts
New incidents are posted to the deployment’s alert webhook the moment they’re detected. The message format works with Slack and Discord incoming webhooks directly, and includes structured JSON for Zapier, Make or n8n — use those to forward alerts to email or SMS. The owner also receives every high and critical alert across all deployments.
Responses
202accepted — includes how many incidents were opened401unknown or missing key ·403deployment not active or origin not registered423the owner has engaged the kill switch429your organization or source IP exceeded its rate limit (seeRetry-After) ·503your organization’s queue is full, retry later200duplicate— theIdempotency-Keyheader was already processed; per-eventeventIdvalues are also de-duplicated
4 · Enterprise APIs
Create a service account under Console → Organization. Keys (ast_svc_…) are scoped to one organization and shown once. Scopes: incidents:read, incidents:write, reports:read, audit:read, scim.
- GET /api/v1/incidents?status=&severity=&since=&before=&limit=
- GET /api/v1/incidents/:id · PATCH { status?, assigneeEmail?, note?, legalHold? }
- GET /api/v1/reports/summary?days=30 · GET /api/v1/audit
- SCIM 2.0 Users: /scim/v2/Users (Groups not supported)
- SAML 2.0: /sso/saml/{org-slug}/metadata · /acs · /login
Signed webhook connectors send the ast.incident.v1 envelope with this header:
X-AST-Signature: t=<unix seconds>,v1=<hex HMAC-SHA256(secret, t + "." + rawBody)>
// Node.js verification
const [t, v1] = header.split(',').map((p) => p.split('=')[1])
const expected = crypto.createHmac('sha256', WHSEC).update(`${t}.${rawBody}`).digest('hex')
const ok = v1?.length === expected.length && crypto.timingSafeEqual(Buffer.from(v1), Buffer.from(expected)) && Date.now() / 1000 - Number(t) < 300