Developer API

API Reference

Integrate LaunchGuard into your CI/CD workflow. Trigger scans, ingest attack chains, and register ongoing Guard monitoring for any host. Bearer tokens start with lg_.

Authentication: All /api/v1/* routes require a Authorization: Bearer lg_YOUR_TOKEN header. The scan endpoint at /api/scan and Guard registration at /api/skill/register-guard are public and require no auth.
Base URLs: https://api.launchguard.dev serves all /api/v1/* routes and /api/skill/register-guard. POST /api/scan is served from https://www.launchguard.dev (the web edge).
Error envelope: All error responses return { "error": string }. Special cases: POST /chains/{id}/run 409 returns { error, sideEffect: "mutation", needsConfirmation: true }; POST /chains/{id}/restore 409 returns { error, titleCollision: true }.
Rate limits: /api/skill/register-guard is rate-limited (429). List endpoints do not paginate; all results are returned.

Scan

POST/api/scanNo auth

Start a scan (free, full findings).

Creates a scan and returns a signed `streamUrl`. GET that URL (backend `/api/scan/stream`) as `text/event-stream`; the stream emits named SSE events: phase, pipeline, model, discovery, endpoints_finalized, subdomains, secrets, supabase_findings, probe_data, done, error. (The stream is NOT JSON — it is SSE.)

Request Body

NameTypeDescription
urlrequiredstringThe URL to scan.
spaboolean | nullEnable SPA crawling mode (Playwright-backed).
maxPagesnumberMax pages to crawl (default: 10).
jsAssetsnumberMax JS bundle files to analyze (default: 5).
ffufbooleanRun ffuf directory brute-force.
includeSubdomainsbooleanAlso scan discovered subdomains.
clientstringAttribution slug.

Responses

StatusDescription
200Scan created
FieldType
scanIdrequiredUuid
streamUrlrequiredstring
400Error
500Error
curl https://www.launchguard.dev/api/scan \ -X POST \ -H "Content-Type: application/json" \ -d '{"url": "acme.ai"}'

Guard

POST/api/skill/register-guardNo auth

Register Ongoing Guard for a URL (headless, no auth).

Request Body

NameTypeDescription
emailrequiredstring
target_urlrequiredstring

Responses

StatusDescription
200Guard registered
FieldType
okrequiredboolean
statusrequiredstring
messagerequiredstring
400Error
429Rate limit exceeded. Retry after the Retry-After header interval.
500Error
curl https://api.launchguard.dev/api/skill/register-guard \ -X POST \ -H "Content-Type: application/json" \ -d '{"email": "you@example.com", "target_url": "https://acme.ai"}'

Connect

POST/api/v1/connectBearer lg_

Link this client to the caller's monitor for a host.

Request Body

NameTypeDescription
targetstringA public URL or host.
urlstringAlias for `target`.

Responses

StatusDescription
200Connected
FieldType
okrequiredboolean
apprequiredstring
monitorIdrequiredstring
dashboardUrlrequiredstring
firstConnectrequiredboolean
watchedTestsrequirednumber
coverageSummaryrequiredobject
400Error
401Invalid or missing bearer token.
404Resource not found.
500Error
curl https://api.launchguard.dev/api/v1/connect \ -X POST \ -H "Authorization: Bearer lg_YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"target": "acme.ai"}'

Coverage & Context

GET/api/v1/contextBearer lg_

One-call aggregate: redacted inventory + unified tests + coverage + findings.

Read-only. NEVER fetches the target site (no scan, no probe). Host-scoped + verified-domain-gated. Everything is run through a deny-by-default structural allowlist — no row samples, secret values, raw bodies, or raw finding titles.

Query Parameters

NameTypeRequiredDescription
targetHoststringrequiredThe app hostname this chain targets (e.g. acme.app).

Responses

StatusDescription
200Context
FieldType
apprequiredstring
monitorIdrequiredstring
dashboardUrlstring
verifiedOwnershiprequiredboolean
lastScanrequiredobject | null
inventoryrequiredobject
testsrequiredobject[]
coverageGapsrequiredobject[]
recommendationsrequiredobject[]
findingsrequiredobject
generatedAtrequiredIsoDate
400Error
401Invalid or missing bearer token.
403Forbidden. Token is valid but lacks permission for this operation.
404Resource not found.
500Error
curl https://api.launchguard.dev/api/v1/context \ -H "Authorization: Bearer lg_YOUR_TOKEN"
GET/api/v1/stacksBearer lg_

The test catalog as data; with ?targetHost, per-domain state + verdicts.

Without targetHost: the bare catalog (valid key required, no host scoping). With targetHost: host-scoped + verified-gated, overlaid with enabled_tests state and a live per-stack verdict. Read-only; never fetches the target.

Query Parameters

NameTypeRequiredDescription
targetHoststringoptionalThe app hostname this chain targets (e.g. acme.app).

Responses

StatusDescription
200Stacks
FieldType
apprequiredstring | null
monitorIdrequiredstring | null
stacksrequiredobject[]
400Error
401Invalid or missing bearer token.
403Forbidden. Token is valid but lacks permission for this operation.
404Resource not found.
500Error
curl https://api.launchguard.dev/api/v1/stacks \ -H "Authorization: Bearer lg_YOUR_TOKEN"
POST/api/v1/coverageBearer lg_

Toggle a default stack's coverage for the caller's verified host.

Request Body

NameTypeDescription
targetHostrequiredstringThe app hostname this chain targets (e.g. acme.app).
stackIdrequiredstring
enabledrequiredboolean
rescanNowboolean

Responses

StatusDescription
200Coverage updated
FieldType
okrequiredboolean
apprequiredstring
monitorIdrequiredstring
stackIdrequiredstring
toggleKeyrequiredstring
enabledrequiredboolean
enabledTestsrequiredobject
appliesOnNextScanrequiredboolean
rescanrequiredobject
400Error
401Invalid or missing bearer token.
402Error
403Forbidden. Token is valid but lacks permission for this operation.
404Resource not found.
409Error
429Rate limit exceeded. Retry after the Retry-After header interval.
curl https://api.launchguard.dev/api/v1/coverage \ -X POST \ -H "Authorization: Bearer lg_YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"targetHost": "acme.app", "stackId": "supabase-rls", "enabled": true}'

Chains

POST/api/v1/chainsBearer lg_

Ingest an attack chain (ChainSpecV2 or script).

Request Body

See IngestChainBody for the full schema.

Responses

StatusDescription
201Chain stored
FieldType
chainIdrequiredstring
autoReplayrequiredboolean
watchedrequiredboolean
sideEffectrequired"none" | "read_only" | "mutation" | "external_action"
notestring
watchNotestring
400Error
401Invalid or missing bearer token.
403Forbidden. Token is valid but lacks permission for this operation.
500Error
curl https://api.launchguard.dev/api/v1/chains \ -X POST \ -H "Authorization: Bearer lg_YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"title": "Unauthenticated data read", "targetHost": "acme.app", "severity": "high"}'
GET/api/v1/chainsBearer lg_

List the caller's chains.

Query Parameters

NameTypeRequiredDescription
targetHoststringoptionalThe app hostname this chain targets (e.g. acme.app).
includeArchivedstringoptionalPass 'true' to include soft-deleted (archived) chains in the results.

Responses

StatusDescription
200Chains
FieldType
targetHostrequiredstring | null
countrequirednumber
chainsrequiredChainListItem[]
400Error
401Invalid or missing bearer token.
500Error
curl https://api.launchguard.dev/api/v1/chains \ -H "Authorization: Bearer lg_YOUR_TOKEN"
POST/api/v1/chains/credentialsBearer lg_

Upload an encrypted Playwright storageState; get an opaque credentialId.

Request Body

See CredentialsBody for the full schema.

Responses

StatusDescription
201Credential sealed
FieldType
credentialIdrequiredstring
kindrequiredstring
identityobject
400Error
401Invalid or missing bearer token.
500Error
curl https://api.launchguard.dev/api/v1/chains/credentials \ -X POST \ -H "Authorization: Bearer lg_YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"storageState": {"cookies": [], "origins": []}, "label": "test-user"}'
GET/api/v1/chains/{id}Bearer lg_

Read one chain's full blueprint.

Path Parameters

NameTypeRequiredDescription
idstringrequired

Responses

StatusDescription
200Chain
FieldType
chainIdrequiredstring
targetHostrequiredstring
titlerequiredstring
severityrequired"critical" | "high" | "medium" | "low"
sourcerequired"scanner" | "ai_agent" | "e2e_test" | "manual" | "import"
sideEffectrequired"none" | "read_only" | "mutation" | "external_action"
declaredSideEffectrequired"none" | "read_only" | "mutation" | "external_action"
derivedSideEffectrequired"none" | "read_only" | "mutation" | "external_action"
statusrequiredstring
lastTestedAtrequiredIsoDate
enabledrequiredboolean
autoReplayrequiredboolean
watchedrequiredboolean
specVersionrequirednumber
createdAtrequiredIsoDate
updatedAtrequiredIsoDate
specrequiredHttpChainSpec | ScriptChainSpec
lastResultstring | null
dispositionstring | null
dispositionReasonstring | null
dispositionBystring | null
dispositionAtIsoDate
dispositionState"none" | "proposed" | "honored" | "stale_spec" | "stale_escalation"
effectiveStatus"red" | "green" | "review"
400Error
401Invalid or missing bearer token.
404Resource not found.
500Error
curl https://api.launchguard.dev/api/v1/chains/CHAIN_ID \ -H "Authorization: Bearer lg_YOUR_TOKEN"
PATCH/api/v1/chains/{id}Bearer lg_

Modify one chain (title/severity/spec/watched).

Path Parameters

NameTypeRequiredDescription
idstringrequired

Request Body

See PatchChainBody for the full schema.

Responses

StatusDescription
200Updated
FieldType
chainIdrequiredstring
targetHostrequiredstring
titlerequiredstring
severityrequired"critical" | "high" | "medium" | "low"
sourcerequired"scanner" | "ai_agent" | "e2e_test" | "manual" | "import"
sideEffectrequired"none" | "read_only" | "mutation" | "external_action"
declaredSideEffectrequired"none" | "read_only" | "mutation" | "external_action"
derivedSideEffectrequired"none" | "read_only" | "mutation" | "external_action"
statusrequiredstring
lastResultrequiredstring | null
lastTestedAtrequiredIsoDate
enabledrequiredboolean
autoReplayrequiredboolean
watchedrequiredboolean
specVersionrequirednumber
createdAtrequiredIsoDate
updatedAtrequiredIsoDate
specrequiredHttpChainSpec | ScriptChainSpec
400Error
401Invalid or missing bearer token.
404Resource not found.
409Title collision
500Error
curl https://api.launchguard.dev/api/v1/chains/CHAIN_ID \ -X PATCH \ -H "Authorization: Bearer lg_YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"severity": "critical", "watched": true}'
DELETE/api/v1/chains/{id}Bearer lg_

Soft-delete (archive) one chain.

Path Parameters

NameTypeRequiredDescription
idstringrequired

Responses

StatusDescription
200Archived
FieldType
okrequiredboolean
chainIdrequiredstring
archivedrequiredboolean
400Error
401Invalid or missing bearer token.
404Resource not found.
500Error
curl https://api.launchguard.dev/api/v1/chains/CHAIN_ID \ -X DELETE \ -H "Authorization: Bearer lg_YOUR_TOKEN"
POST/api/v1/chains/{id}/restoreBearer lg_

Un-archive one chain.

Path Parameters

NameTypeRequiredDescription
idstringrequired

Responses

StatusDescription
200Restored
FieldType
okrequiredboolean
chainIdrequiredstring
restoredrequiredboolean
400Error
401Invalid or missing bearer token.
404Resource not found.
409Title collision on restore. Returns { error, titleCollision: true } — rename the chain before restoring.
500Error
curl https://api.launchguard.dev/api/v1/chains/CHAIN_ID/restore \ -X POST \ -H "Authorization: Bearer lg_YOUR_TOKEN"
POST/api/v1/chains/{id}/runBearer lg_

Re-execute a stored chain through the guarded replay engine.

Path Parameters

NameTypeRequiredDescription
idstringrequired

Query Parameters

NameTypeRequiredDescription
confirmMutationstringoptionalSet true to allow a mutating chain to fire real writes.

Request Body

NameTypeDescription
confirmMutationboolean | stringOpt-in to fire REAL writes for a mutating chain.

Responses

StatusDescription
200Run result
FieldType
runIdrequiredstring | null
resultrequiredstring
healthstring
reasonstring | null
matchedboolean
regressionboolean
persistedrequiredboolean
observedObservedSnapshot
proofProof
reproducedReproduced
400Error
401Invalid or missing bearer token.
403Forbidden. Token is valid but lacks permission for this operation.
409Chain disabled or mutation gate triggered. Returns { error, sideEffect: "mutation", needsConfirmation: true } — pass confirmMutation: true to allow real writes.
500Error
curl https://api.launchguard.dev/api/v1/chains/CHAIN_ID/run \ -X POST \ -H "Authorization: Bearer lg_YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"confirmMutation": false}'
POST/api/v1/chains/{id}/dispositionBearer lg_

Set/clear the durable disposition layer.

Path Parameters

NameTypeRequiredDescription
idstringrequired

Request Body

NameTypeDescription
dispositionrequired"accepted" | "proposed"
reasonstringRequired + non-empty when setting.

Responses

StatusDescription
200Disposition view
FieldType
chainIdrequiredstring
lastResultstring | null
dispositionstring | null
dispositionReasonstring | null
dispositionBystring | null
dispositionAtIsoDate
dispositionState"none" | "proposed" | "honored" | "stale_spec" | "stale_escalation"
effectiveStatus"red" | "green" | "review"
400Error
401Invalid or missing bearer token.
403Disposition change not permitted in the chain's current state (e.g. already in an incompatible state).
404Resource not found.
409Disposition conflict — the chain state changed since you read it.
500Error
503Disposition service temporarily unavailable. Safe to retry with backoff.
curl https://api.launchguard.dev/api/v1/chains/CHAIN_ID/disposition \ -X POST \ -H "Authorization: Bearer lg_YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"disposition": "accepted", "reason": "Acknowledged risk, mitigated with rate limit"}'
POST/api/v1/chains/{id}/run/script/startBearer lg_

Start an async script-chain run; get a runId + SSE progress URL.

Path Parameters

NameTypeRequiredDescription
idstringrequired

Query Parameters

NameTypeRequiredDescription
confirmMutationstringoptionalSet true to allow a mutating chain to fire real writes.

Request Body

NameTypeDescription
confirmMutationboolean | stringOpt-in to fire REAL writes for a mutating chain.

Responses

StatusDescription
202Run started in the background. Returns { runId, progressUrl } — subscribe to the progress SSE stream at progressUrl.
FieldType
runIdrequiredstring
progressUrlrequiredstring
400Error
401Invalid or missing bearer token.
403Forbidden. Token is valid but lacks permission for this operation.
404Resource not found.
409Disabled, or mutating without confirmation
500Error
curl https://api.launchguard.dev/api/v1/chains/CHAIN_ID/run/script/start \ -X POST \ -H "Authorization: Bearer lg_YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"confirmMutation": false}'
GET/api/v1/chains/{id}/runs/{runId}/progressBearer lg_

Live SSE progress for an async script-chain run.

GET this as `text/event-stream`; the stream emits named SSE events: `step` (per-step running/passed/failed progress) and a terminal `done` (the chain verdict + health + optional trace/replay handles). (The stream is NOT JSON — it is SSE.)

Path Parameters

NameTypeRequiredDescription
idstringrequired
runIdstringrequired

Responses

StatusDescription
200SSE stream of step + done events
400Error
401Invalid or missing bearer token.
404Resource not found.
curl https://api.launchguard.dev/api/v1/chains/CHAIN_ID/runs/RUNID/progress \ -H "Authorization: Bearer lg_YOUR_TOKEN"
GET/api/v1/chains/{id}/traces/{token}Bearer lg_

Download an owner-only, expiring trace.zip for a run.

Returns the captured Playwright trace.zip (credential-bearing). Owner-only and expiring: a non-owner or expired token returns 404 (it never confirms existence).

Path Parameters

NameTypeRequiredDescription
idstringrequired
tokenstringrequired

Responses

StatusDescription
200The trace.zip archive
400Error
401Invalid or missing bearer token.
404Resource not found.
curl https://api.launchguard.dev/api/v1/chains/CHAIN_ID/traces/TOKEN \ -H "Authorization: Bearer lg_YOUR_TOKEN"
GET/api/v1/chains/{id}/runs/{runId}/videoBearer lg_

Owner-only gated HLS replay proxy for a script-chain run recording.

Streams the Browserbase session recording through a gated proxy; the Browserbase api key is NEVER exposed. Without `?segment`, returns the rewritten HLS m3u8 manifest; with `?segment`, returns a single media/init segment. 404 when the chain/run isn't the caller's or no recording exists.

Path Parameters

NameTypeRequiredDescription
idstringrequired
runIdstringrequired

Query Parameters

NameTypeRequiredDescription
segmentstringoptional

Responses

StatusDescription
200HLS manifest (no ?segment) or a single media/init segment (with ?segment)
401Invalid or missing bearer token.
404Resource not found.
curl https://api.launchguard.dev/api/v1/chains/CHAIN_ID/runs/RUNID/video \ -H "Authorization: Bearer lg_YOUR_TOKEN"

Type Reference

Shared schemas referenced across multiple endpoints.

Severity

Finding/chain severity.

"critical""high""medium""low"

SideEffect

Declared/derived side-effect class.

"none""read_only""mutation""external_action"

ChainSource

Defaults to ai_agent.

"scanner""ai_agent""e2e_test""manual""import"

ChainMethod

"GET""POST""PUT""PATCH""DELETE"

TargetRef

Host enum resolved against spec.allowedTargets (never free-form).

"primary""supabase""api"

Disposition

'accepted' | 'proposed' | null (null clears the disposition).

"accepted""proposed"

DispositionState

"none""proposed""honored""stale_spec""stale_escalation"

EffectiveStatus

"red""green""review"

CredentialsBody

A Playwright storageState (raw or wrapped in { storageState, ... }).

Option 1 (storageState)

NameTypeDescription
storageStaterequiredstring | objectPlaywright storageState (either raw JSON or wrapped in { storageState, label, metadata }).
labelstringHuman-readable label for a chain step or stored credential.
metadataobject
identityobject

Option 2 (cookies/origins)

NameTypeDescription
cookiesobject[]
originsobject[]

PatchChainBody

At least one of title|severity|spec|watched must be provided.

NameTypeDescription
titlestringHuman-readable title, unique per host.
severity"critical" | "high" | "medium" | "low"Finding severity level.
specHttpChainSpec | ScriptChainSpec
watchedbooleantrue = Guard mode (re-runs on deploy); false = Proof only (default).

IngestChainBody

NameTypeDescription
titlerequiredstringHuman title (unique per host).
targetHostrequiredHostThe app hostname this chain targets (e.g. acme.app).
severityrequired"critical" | "high" | "medium" | "low"Finding severity level.
source"scanner" | "ai_agent" | "e2e_test" | "manual" | "import"Who generated this chain (defaults to ai_agent).
binstringBin/namespace tag for organizing chains.
watchedbooleantrue=Guard (re-runs on deploy); default false=Proof.
artifactstringDefaults to http.
specHttpChainSpec | ScriptChainSpecThe ChainSpecV2 (HTTP chains).
scriptstring@playwright/test source (artifact:script).
intentstringChain intent: security or functional.
secureWhenstringWhen pass, the test is secure when assertions pass.
sideEffect"none" | "read_only" | "mutation" | "external_action"
destructivebooleanMark chain as potentially destructive.
credentialIdstringReference to a stored Playwright credential set.
allowedTargetsobject

HttpChainSpec

NameTypeDescription
versionrequirednumber
stepsrequiredChainStep[]
assertionrequiredSecurityAssertion
authrequiredobject
sideEffectrequired"none" | "read_only" | "mutation" | "external_action"
allowedTargetsrequiredAllowedTargets
envobject
inventoryHashstring

ScriptChainSpec

NameTypeDescription
versionrequirednumber
artifactrequiredstringChain type: http (default) or script (Playwright).
stepsrequiredChainStep[]
assertionrequiredSecurityAssertion
authrequiredobject
sideEffectrequired"none" | "read_only" | "mutation" | "external_action"
allowedTargetsrequiredAllowedTargets
scriptrequiredScriptChainPayload
envobject
inventoryHashstring

ChainStep

NameTypeDescription
orderrequirednumber
idrequiredstring
labelrequiredstringHuman-readable label for a chain step or stored credential.
requestrequiredChainRequestSpec
rolerequiredstring
authRefstring
extractChainExtractor[]
sideEffectrequired"none" | "read_only" | "mutation" | "external_action"

ChainRequestSpec

NameTypeDescription
methodrequired"GET" | "POST" | "PUT" | "PATCH" | "DELETE"
targetrequired"primary" | "supabase" | "api"Host enum resolved against spec.allowedTargets: 'primary' | 'supabase' | 'api'. Never a free-form URL.
pathrequiredstring
queryobject
headersobject
bodyobject
timeoutMsnumber

ChainExtractor

NameTypeDescription
asrequiredstring
fromrequiredstring
exprstring
indexnumber
requiredrequiredboolean

SecurityAssertion

NameTypeDescription
successStatusInrequirednumber[]
fixedStatusInrequirednumber[]
crossTenantobject
minTotalRowsnumber
jsonPathsPresentstring[]
bodyContainsAllstring[]
contentTypeIncludesstring
errorEnvelopeContainsAnystring[]

ChainAuthRef

NameTypeDescription
credentialIdrequiredstring | nullReference to a stored Playwright credential set.
injectrequiredstring

AllowedTargets

NameTypeDescription
primaryrequiredstring
supabasestring
apistring

Proof

Option 1 (RowsProof)

NameTypeDescription
renderrequiredstring
countrequirednumber
columnsrequiredstring[]
sampleRowsrequiredobject[]Each value is value-masked before it leaves the engine.
moreCountrequirednumber
countIsFloorboolean

Option 2 (RecordWithOwnerProof)

NameTypeDescription
renderrequiredstring
foreignRowCountrequirednumber
sampleRowrequiredobject
ownerValuerequiredstring
comparedAgainstUserIdrequiredstring

Option 3 (JudgmentOnlyProof)

NameTypeDescription
renderrequiredstring
reasonrequiredstring
codeRefstring

ObservedSnapshot

NameTypeDescription
statusrequirednumber
contentTyperequiredstring
rowCountrequirednumber | null
jsonKeysrequiredstring[]
bodyPreviewrequiredstringValue-masked before it leaves the engine.

Reproduced

NameTypeDescription
passedrequirednumber
totalrequirednumber