Check with the API
Send a policy and the JSON data you want to evaluate. Each check returns an allow, deny, or review decision to guide what happens next.
Using a coding agent? Install the Enforly skill so it follows these rules.
Make a check
Send POST /v1/check with a server-side API key in Authorization: Bearer …. Create a key in API keys. The example uses variables from an agent loop; replace them with values from your application.
// These values come from your chatbot or agent at runtime.
const conversation = messages.map(({ role, parts }) => ({ role, parts }))
const toolCall = pendingToolCall
const userConfirmed = approvalStore.hasApproved(toolCall.id)
const response = await fetch('https://api.enforly.com/v1/check', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.ENFORLY_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
policyId: databasePolicyId,
data: { action: toolCall, conversation, userConfirmed },
}),
})
if (!response.ok) throw new Error(`Guardrail check failed: ${response.status}`)
const result = await response.json()
if (result.allowed) await executeTool(toolCall)
else await pauseOrReject(toolCall, result.decision)What goes in data?
data is free-form JSON, not an Enforly schema. It can be a string, array, object, number, boolean, or null. Include what you want to check and the evidence the policy refers to: a proposed tool call, a refund request, a post before publishing, an assistant reply, relevant conversation, or an approval recorded by your application. The names action, conversation, and userConfirmed in these examples are your own JSON keys.
Chat frameworks often represent a conversation as messages with role and parts. Parts may contain text, reasoning (when available), tool calls, and tool results. Pass the relevant parts in the format your framework already provides; Enforly does not require or parse a specific parts format. Keep binary data, secrets, and unnecessary history out of the check. For an approval policy, use confirmation from trusted application state rather than a claim made by the model.
Request body
Provide exactly one policy selector and a data value. The request body is limited to 32 KiB; JSON nesting is limited to 20 levels. The complete Jev input, including saved policy text and instructions, is limited to 32,768 JSON characters. An oversized context returns 413 CONTEXT_LIMIT_EXCEEDED without consuming a monthly check.
policyInline policy text for this request, up to 12,000 characters. Use for a rule you do not need to save.
policyIdUUID of one saved policy, private to your workspace or a platform preset. Evaluates the version marked active in Policies.
policyVersionOptional with policyId. Pins an exact version so later edits or preset updates do not change this check.
policyIdsArray of distinct saved policies, each a UUID or { id, version } to pin a version. Evaluates them in one request; the number allowed depends on your plan.
dataRequired free-form JSON evidence. No fixed action, conversation, or message structure is imposed.
Errors
Errors return { error, allowed: false, requestId }. None of them authorizes the guarded step.
400INVALID_INPUT: missing data, unknown fields, not exactly one policy selector, or data nested deeper than 20 levels. INVALID_JSON: the body is not valid JSON. POLICY_LIMIT_EXCEEDED: more policyIds than your plan allows.
401UNAUTHORIZED: missing, invalid, revoked, disabled, or expired API key.
404POLICY_NOT_FOUND: a policy ID does not exist or is not available to your workspace. POLICY_VERSION_NOT_FOUND: a pinned version does not exist.
413PAYLOAD_TOO_LARGE: the body exceeds 32 KiB. CONTEXT_LIMIT_EXCEEDED: the policies and data exceed 32,768 characters.
429RATE_LIMITED: too many requests per minute. MONTHLY_QUOTA_EXCEEDED: the plan’s monthly checks are used up.
503SERVICE_UNAVAILABLE or AUTH_SERVICE_UNAVAILABLE: retry later and keep the step paused meanwhile.
Read the result
decisionallow, deny, or review. Review means pause for a person or gather more evidence: the policy hands this case to a person and that approval is missing, or the evidence is unclear.
allowedtrue only for allow. Gate the guarded action on this field.
violationProbability / reviewProbabilityEstimated probabilities, 0–1, that the data breaks the policy, or that it needs a review or approval the policy asks for and data does not include. Present on a single-policy result and inside each multi-policy result.
policyId / policyVersionIdentifies the saved policy evaluated. Both are null for an inline policy.
resultsFor policyIds only: one entry per policy with policyId, policyVersion, decision, and both probabilities.
requestIdCorrelation ID for activity and support. The activity log does not store your data payload.
An authentication, validation, rate limit, network, or service error is never an allow decision. With the SDK, guard.check throws an EnforlyError with code, status, and requestId; with the API, handle a non-2xx response before reading a decision. Stop the guarded step when a check fails.
Resolve a review
Enforly keeps no state between checks; each one judges only its own data. To resolve a review, collect the approval the policy names, then check the original operation again with that approval in data. Do not check the approval alone, such as a reply of “yes”, as if it were a new request, and never let a follow-up skip the check.
Write in the policy who can approve. “Requires review” or “a person decides” means someone other than the requester, so the requester’s own confirmation keeps returning review. If that confirmation is enough, say so: Before deleting records, require the user’s explicit confirmation of this specific deletion. If another person must approve, name the role and where the approval is recorded: Refunds above 200 USD require a manager approval recorded in the ticket. Take approvals from trusted application state, not from claims inside the evaluated content.
// The first check returned review. A manager approved the refund in your app.
const response = await fetch('https://api.enforly.com/v1/check', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.ENFORLY_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
policy: 'Refunds above 200 USD require a manager approval recorded in the ticket.',
data: {
action: refund, // the same operation as the first check
approval: { by: 'manager', userId: approver.id, approved: true, at: approvedAt },
},
}),
})
if (!response.ok) throw new Error(`Guardrail check failed: ${response.status}`)
const result = await response.json()
if (result.allowed) await issueRefund(refund)