POST /v1/check

The core endpoint. Call this before your agent touches user data. A check accepts one or more scopes and returns one decision plus one receipt envelope per scope.

See Decisions and Attributes for the full list of supported verbs, reason codes, request attributes, and scope constraints.

Request

POST /v1/check
Authorization: Bearer allowly_l1_s001_...
Content-Type: application/json
{
  "authorization_id": "auth_01HXZ2A0K1L2M3N4P5Q6R7S8T9",
  "scopes": ["contact.enrich", "outreach.send"],
  "resource": "edge:emp_8821:conn_9f2a",
  "session_id": "sess_7f2",
  "context": {
    "initiated_by": "user",
    "origin": "chat"
  }
}
FieldRequiredDescription
authorization_idyesThe authorization authorizing this scope. Returned when you created the authorization via POST /v1/authorizations.
scopesyesArray of permission names being checked (e.g. email.send, contact.enrich). Each must match a scope on the authorization. Empty arrays and duplicate scopes are rejected.
resourcenoIdentifier of the action target. Omit or use null if the action has no specific resource.
session_idnoCustomer-assigned session label, recorded in the receipt for later querying.
estimated_cost_microsrequired for budgeted authorizationsEstimated action cost in micro-USD. Budgeted checks currently support exactly one scope. See Budget Gate.
contextnoOpaque object of additional facts, recorded in the receipt.

user_id and agent_id are not in the request — they are looked up from the authorization. This prevents spoofing.

Response — allow

{
  "authorization_id": "auth_01HXZ2A0K1L2M3N4P5Q6R7S8T9",
  "user_id": "emp_8821",
  "agent_id": "referral_outreach",
  "authorization_expires_at": "2026-12-31T00:00:00Z",
  "policy_version": "2026-04-17.1",
  "results": {
    "outreach.send": {
      "decision": "allow",
      "reason": "authorization_granted_scope_active",
      "receipt": {
        "status": "pending",
        "receipt_id": "rcp_01HXZ2B...",
        "ready_at_estimate": "2026-04-21T14:32:18.482Z",
        "url": "https://api.allowly.ai/v1/receipts/rcp_01HXZ2B..."
      }
    }
  }
}

Response — deny

{
  "authorization_id": "auth_01HXZ2A...",
  "user_id": "emp_8821",
  "agent_id": "referral_outreach",
  "authorization_expires_at": "2026-12-31T00:00:00Z",
  "policy_version": "2026-04-17.1",
  "results": {
    "outreach.send": {
      "decision": "deny",
      "reason": "authorization_revoked",
      "receipt": {
        "status": "pending",
        "receipt_id": "rcp_01HXZ2C...",
        "ready_at_estimate": "2026-04-21T14:32:18.482Z",
        "url": "https://api.allowly.ai/v1/receipts/rcp_01HXZ2C..."
      }
    }
  }
}

Every denial is also receipted — the signed record of what was blocked is audit evidence too.

Response — budget evaluated

If the authorization has a budget, each evaluated result includes a budget block. An over-budget action returns deny with reason: "budget_exceeded".

{
  "authorization_id": "auth_01HXZ2A...",
  "user_id": "emp_8821",
  "agent_id": "referral_outreach",
  "authorization_expires_at": "2026-12-31T00:00:00Z",
  "policy_version": "2026-04-17.1",
  "results": {
    "llm.enrich": {
      "decision": "allow",
      "reason": "authorization_granted_scope_active",
      "budget": {
        "limit_micros": 50000000,
        "spent_micros": 120000,
        "estimated_cost_micros": 24000,
        "spent_after_micros": 144000
      },
      "receipt": {
        "status": "pending",
        "receipt_id": "rcp_01HXZ2C...",
        "ready_at_estimate": "2026-04-21T14:32:18.482Z",
        "url": "https://api.allowly.ai/v1/receipts/rcp_01HXZ2C..."
      }
    }
  }
}

Response — confirm

{
  "authorization_id": "auth_01HXZ2A...",
  "user_id": "emp_8821",
  "agent_id": "referral_outreach",
  "authorization_expires_at": "2026-12-31T00:00:00Z",
  "policy_version": "2026-04-17.1",
  "results": {
    "outreach.send": {
      "decision": "confirm",
      "reason": "scope_requires_user_confirmation",
      "confirm_nonce": "cnf_01HXZ...",
      "confirm_expires_at": "2026-04-21T14:47:17.482Z",
      "confirm_prompt_hint": "outreach.send",
      "receipt": {
        "status": "pending",
        "receipt_id": "rcp_01HXZ2D...",
        "ready_at_estimate": "2026-04-21T14:32:18.482Z",
        "url": "https://api.allowly.ai/v1/receipts/rcp_01HXZ2D..."
      }
    }
  }
}

Show the user a prompt using confirm_prompt_hint, then call POST /v1/confirmations/{nonce} with their response.

Response — escalate

{
  "authorization_id": "auth_01HXZ2A...",
  "user_id": "emp_8821",
  "agent_id": "referral_outreach",
  "authorization_expires_at": "2026-12-31T00:00:00Z",
  "policy_version": "2026-04-17.1",
  "results": {
    "candidate.delete": {
      "decision": "escalate",
      "reason": "escalation_required",
      "escalation": {
        "escalation_id": "esc_01HXZ...",
        "status": "pending",
        "escalation_to": "compliance",
        "expires_at": "2026-04-22T14:32:17.482Z"
      },
      "escalation_id": "esc_01HXZ...",
      "escalation_to": "compliance",
      "escalation_expires_at": "2026-04-22T14:32:17.482Z",
      "receipt": {
        "status": "pending",
        "receipt_id": "rcp_01HXZ2E...",
        "ready_at_estimate": "2026-04-21T14:32:18.482Z",
        "url": "https://api.allowly.ai/v1/receipts/rcp_01HXZ2E..."
      }
    }
  }
}

Route the request to the configured approver, then call POST /v1/escalations/{escalation_id}/resolve. If approved, re-call /check with the same authorization, scope, and resource — the next result returns allow once.

Decision values

For the complete reason-code table, see Decisions and Attributes.

DecisionReason codes
allowauthorization_granted_scope_active
denyauthorization_not_found, authorization_revoked, authorization_expired, scope_not_authorized, rate_limit_exceeded, resource_tombstoned, budget_exceeded, escalation_rejected
confirmscope_requires_user_confirmation
escalateescalation_required

The receipt envelope

Each item in results has a receipt field. The default response is a pending envelope:

{
  "status": "pending",
  "receipt_id": "rcp_01HXZ2B...",
  "ready_at_estimate": "2026-04-21T14:32:18.482Z",
  "url": "https://api.allowly.ai/v1/receipts/rcp_01HXZ2B..."
}

The signed receipt is produced asynchronously. Fetch it at url when you need the audit artifact. See Receipts.

Inline signing (?wait=true)

Add ?wait=true to block up to 5 seconds for signing to complete. Returns the signed shape if it finishes in time, otherwise falls back to pending. Use this only when you need synchronous audit evidence.

POST /v1/check?wait=true

Latency

The decision is immediately usable. Receipt signing happens off the critical path.