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.

Server-side JavaScript · fetch
// 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.

policy

Inline policy text for this request, up to 12,000 characters. Use for a rule you do not need to save.

policyId

UUID of one saved policy, private to your workspace or a platform preset. Evaluates the version marked active in Policies.

policyVersion

Optional with policyId. Pins an exact version so later edits or preset updates do not change this check.

policyIds

Array 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.

data

Required 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.

400

INVALID_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.

401

UNAUTHORIZED: missing, invalid, revoked, disabled, or expired API key.

404

POLICY_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.

413

PAYLOAD_TOO_LARGE: the body exceeds 32 KiB. CONTEXT_LIMIT_EXCEEDED: the policies and data exceed 32,768 characters.

429

RATE_LIMITED: too many requests per minute. MONTHLY_QUOTA_EXCEEDED: the plan’s monthly checks are used up.

503

SERVICE_UNAVAILABLE or AUTH_SERVICE_UNAVAILABLE: retry later and keep the step paused meanwhile.

Read the result

decision

allow, 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.

allowed

true only for allow. Gate the guarded action on this field.

violationProbability / reviewProbability

Estimated 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 / policyVersion

Identifies the saved policy evaluated. Both are null for an inline policy.

results

For policyIds only: one entry per policy with policyId, policyVersion, decision, and both probabilities.

requestId

Correlation 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.

Server-side JavaScript · fetch · re-check with the approval
// 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)
Prefer a typed client? Open SDK docs