Hooks exist at three levels — agent, org, and platform. They are merged (agent ∪ org ∪ platform). The agent UI manages the agent’s own hooks and shows org/platform hooks as read-only. An org/platform hook can be marked immutable so it always applies and cannot be disabled or overridden below.
How a hook works
For a server-side hook (http / workspace target) the platform sends your endpoint a JSON request describing the event, and your endpoint answers with a decision that the pipeline applies:
Lifecycle events
A hook subscribes to one or more events:Targets
Thetarget.type decides where the hook runs.
http — call your own endpoint
The hook POSTs the event payload to a URL and uses the response to allow / modify / block. The endpoint is most often a Builder automation exposed as a webhook, so you stay inside Prisme.ai (RBAC, secrets, audit) — this is the recommended way to run your own hook logic.
The request carries only
Content-Type: application/json (plus the platform’s own x-prismeai-workspace-id). Custom request headers and per-request auth are not forwarded — put any secret the endpoint needs in the workspace itself (Builder secrets / config), or in a non-guessable path segment of the URL.workspace — call an automation by slug
Reference a Builder automation by workspace_slug + automation_slug instead of a full URL — the platform builds the webhook call for you and sends the same { event, content, callback?, options? } body as http. The target automation must declare when: { endpoint: true }.
target.options (optional) is forwarded verbatim so a single automation can serve several hooks with different static config — read it as {{body.options}}.
workspace targets fail closed: if the target returns HTTP ≥ 400, or a body with no decision (e.g. the automation doesn’t exist or is missing endpoint: true), the hook resolves to an error and your on_error policy applies — so on_error: "deny" really does block. A handful of platform test slugs (_mock-hook-*) are dispatched internally rather than over HTTP.client — declarative browser policy (file gate)
A client hook is evaluated in the browser against a file’s extracted metadata, before any upload. No external call, no third-party JavaScript — see The client-side file gate. For client targets mode is ignored (it is always a synchronous, in-browser check) and the only valid event is before_upload.
Execution modes
mode controls the server-side timing of http / workspace hooks. It is ignored for client targets.
async and stream are advanced modes with a callback contract — see Async & stream callbacks. sync is what the vast majority of hooks use.What your hook receives
Every server-side hook is aPOST with this body:
When the target is a Builder automation, the whole POST body is available as
{{body}} — so you read {{body.event}}, {{body.content.text}}, {{body.callback.token}}, etc.content object depends on the event:
What your hook must answer
Async hook must return a decision object:
score and tags are optional — they are recorded on the hook.invoked analytics event but do not by themselves change the outcome.
Decision precedence
When several hooks fire on the same event, their decisions are merged with this precedence:deny blocks the payload regardless of what the other hooks returned.
Signalling an error
If your endpoint cannot make a decision, return an object with anerror and no decision:
on_error policy (allow = fail-open, deny = fail-closed). A thrown HTTP error, a non-JSON response, or a timeout is treated the same way.
Examples
Abefore_message PII gate that blocks or redacts:
after_llm guard that enforces citations:
Behavior controls
Error handling & resilience
Hooks are designed to never take the agent down:on_errorpolicy — every failure (timeout, error response,{ "error": ... }body) resolves toallowordenyper the hook’s setting.- Circuit breaker — if a hook fails repeatedly (5 failures within 60s) it is temporarily skipped for ~60s and its
on_errorpolicy applies to skipped calls. It resets on the next success. - Rate limiting — beyond
rate_limit_per_min, further calls are skipped (again honouringon_error).
hook.invoked event (with decision, duration_ms, score, tags, error) that you can inspect in the activity feed / analytics.
Async & stream callbacks
async and stream hooks respond in two phases: an immediate acknowledgement, then a callback into the task. The request body carries a callback object:
X-Hook-Token header (an Authorization: Bearer <token> header is also accepted).
async (before_file_ingest)
Acknowledge immediately, then finish the task when your scan completes:
stream (before_llm)
Your endpoint takes over the LLM step and pushes events to callback.url:
The client-side file gate
The most commonclient hook is a file-classification gate: read a document’s metadata locally and reject non-conformant files before they ever leave the browser (e.g. a document classified above the level your SaaS is allowed to process).
Policy rules
Rules are evaluated with AND semantics — the first rule the file does not satisfy whoseon_fail is deny blocks the upload.
in / equals / matches / exists are fail-closed: a missing property fails the rule, so an unmarked document is blocked by a deny rule. not_in is fail-open (nothing to forbid when the property is absent) — pair it with an exists rule to also block unmarked files.Metadata namespaces
The extractor flattens each file’s metadata into namespaced keys you target withproperty:
Microsoft Purview / MIP sensitivity labels
MIP stores its label differently depending on the Office version and the file type — in thedocMetadata/LabelInfo.xml part (modern Office), as MSIP_Label_<guid>_* custom properties (legacy Office, PDF via Acrobat), or packed into a single msip_labels header (Outlook .eml). The extractor normalizes all of them into the same flat keys, which also match what the server-side crawler (Tika) emits — so one rule works everywhere:
A typical gate — only documents carrying one of the approved labels may be uploaded:
id of the label in your Microsoft Purview compliance portal; you can also read it from a labeled document (unzip -p doc.docx docMetadata/LabelInfo.xml) or from the crawler’s extracted metadata (mip:label:id). Removed (removed="1") and disabled labels are ignored.
Files whose metadata cannot be read in the browser — label-encrypted Office files (the label encrypts the container), Outlook
.msg, .pfile — yield an empty metadata bag, so a fail-closed deny rule blocks them. That is the safe default: a document that cannot prove conformance does not go through.Org & platform hooks
Hooks defined at the org or platform level apply to every agent in scope. Setimmutable: true to make a policy mandatory: it always applies and cannot be disabled or overridden by an agent. In the agent UI these appear as read-only / locked, with locked_by indicating org or platform. Only org/platform configs may set immutable — an agent-level hook that tries to is rejected.
Limits
- Up to 10 hooks per agent.
- Unique
idper hook; each hook must declare at least one event. - Default rate limit: 1000 invocations/minute per hook.
httptargets must usehttps://and may not point at internal/private addresses.