Skip to content
Anlyon
Esc
↑↓navigate↵open⌘Jpreview

Decide an end user's approval

The end user’s answer, relayed by your app. Approving runs the parked call; the request-bound preview, expiry and receipts work as for any approval. An approval of another end user, or one the team decides, answers 404.

POST/api/v2/end-users/{endUserId}/approvals/{approvalId}/decide
Authorization
AuthorizationBearer token (Anlyon API key) · headerrequired

Workspace API key sent as Authorization: Bearer <key>.

or
better-auth.session_tokenAPI key · cookierequired

Browser session used by dashboard-only operations.

Path parameters
endUserIdstringrequired

Your own id for the end user. 1 to 128 characters of letters, digits and . _ : @ -. URL-encode it.

min length 1 · max length 128 · matches ^[A-Za-z0-9._:@-]{1,128}$
approvalIdstringrequired

Public approval id (apr_...).

min length 1 · max length 100
Header parameters
X-Request-Idstring

Optional caller correlation ID. Unsafe or oversized values are replaced.

max length 128
Anlyon-End-Userstring

The end user this call acts for: your own id for them, 1 to 128 characters of letters, digits and . _ : @ -. Accepted only with an API key, which stays on your server; a session or an OAuth token that sends it is refused. A key created with endUserRequired must send it on every action call (400 END_USER_REQUIRED). On an /end-users/{endUserId} route it must name the same end user as the path.

min length 1 · max length 128 · matches ^[A-Za-z0-9._:@-]{1,128}$
Request body
requiredapplication/json
decisionstringrequired
Allowed:approvedeny
reasonstring

Recorded as the decision note.

max length 1000
Responses
200

The decision

successbooleanrequired
Allowed:true
dataobjectrequired
Show properties
approvalApprovalrequired
Show properties
idstringrequired
kindstringrequired

function_plan: the writes a hosted function's plan run recorded, bound to the plan's digest in payload.planDigest.

Allowed:actioncustomfunction_plan
statusstringrequired
Allowed:pendingapproveddeniedexpired
titlestringrequired
descriptionstring | nullrequired
payloadobjectrequired

Secret-safe review payload.

decisionNotestring | nullrequired
decidedByApprovalActor | null

The recorded reviewer who finalized the decision, not all voters. Null for pending, expired, automated or unattributed decisions. Available to approval readers; not copied into invocation responses.

Show properties
Any of:
ApprovalActor
typestringrequired
Allowed:api_keyuser
idstringrequired

Stable recorded reviewer identity. Never an API key value.

displayNamestring | nullrequired

Null when no historical display name was recorded.

null
null
votesApprovalVote[]

Recorded votes in chronological order on detail reads, including long-poll results. Omitted on list, create and decide responses; fetch the detail to audit all reviewers.

Show properties
Array of ApprovalVote
decisionstringrequired
Allowed:approvedeny
decidedByApprovalActor | nullrequired
Show properties
Any of:
ApprovalActor
ApprovalActor
null
null
notestring | nullrequired
selfApprovedbooleanrequired

True when an app acting for the decider, or an API key they created, requested the approval. Allowed only while the decider is the only member who can decide approvals in its environment; with a second one, the request answers 403 SELF_APPROVAL_NOT_ALLOWED.

decidedAtstring<date-time>required
requiredApprovalsintegerrequired

Distinct approvers needed (N-of-M), as resolved from the governing policy when the approval was created.

min 1
approvedCountintegerrequired

Approvals recorded so far.

min 0
matchedPolicyIdstring | nullrequired

The policy that governed this approval, as recorded when it was created. Null when no policy matched (the default gate applied) and on approvals recorded before policies existed.

matchedPolicyVersioninteger | nullrequired

The version of that policy at the time. Null exactly when matchedPolicyId is null.

policyExplanationstring | nullrequired

A human-readable account of how the policy was applied. Null on approvals recorded before it was kept. It is the approval's own record; an invocation carries its own decision and does not need this.

decisionOriginstring | nullrequired

Who decided. Persisted, not inferred from status. Null while pending. unknown marks a decision made before origin was recorded whose evidence does not settle it; it is never guessed. assistant is an approval by opt-in Anlyon Vigil inside the limits an admin set; it never denies.

Allowed:humanpolicysystemunknownassistantnull
endUserIdstring | nullrequired

The end user the gated call was made for (Anlyon-End-User), or null for a call with the workspace's own accounts. erased~<hash> once that end user is erased.

deciderstringrequired

Who decides it. end_user: the end user it was made for, in your app, through /api/v2/end-users/{endUserId}/approvals (a policy with decidedBy: end_user). Such an approval is not in the team's inbox or Slack, and the team's decide routes answer 404 for it. Not decidedBy, which is the reviewer.

Allowed:teamend_user
expiresAtstring<date-time>required
decidedAtstring<date-time> | nullrequired
createdAtstring<date-time>required
adviceobject

Anlyon Vigil's suggestion, on dashboard (session) responses only and only for workspaces that opted in. API-key callers never receive it.

Show properties
statusstringrequired
Allowed:pendingreadyfailedskipped
statusReasonstring | nullrequired

Why advice failed or was skipped, e.g. quota_exceeded, timeout, already_decided.

modelstring | nullrequired

Vigil's public model version. Auto-approve thresholds are calibrated per version.

recommendationstring | nullrequired
Allowed:approvedenyreviewnull
risknumber | nullrequired

Expected harm if approving were wrong, 0 routine to 4 critical.

min 0 · max 4
riskLevelstring | nullrequired
Allowed:routinelowmoderatehighcriticalnull
confidencenumber | nullrequired
min 0 · max 1
reasonsstring[]required
flagsobject | nullrequired
Show properties
injectionSuspectednumber | nullrequired
min 0 · max 1
consistentWithHistorynumber | nullrequired
min 0 · max 1
amountUnusualnumber | nullrequired
min 0 · max 1
historyobject | nullrequired

This agent and action over the last 30 days.

Show properties
approvedintegerrequired
min 0
deniedintegerrequired
min 0
maxAmountnumber | nullrequired
medianAmountnumber | nullrequired
auditRequestedbooleanrequired

This Vigil decision was sampled for a person to check.

auditVerdictstring | nullrequired
Allowed:agreedisagreenull
createdAtstring<date-time>required
completedAtstring<date-time> | nullrequired
invocationInvocation
Show properties
idstringrequired
effectIdstring | nullrequired

The governed effect this invocation created, for a governed action (an adapter or a declaration). Its outcome, evidence and recovery are at GET /api/v2/actions/effects/{id}. Null for template actions.

endUserIdstring | nullrequired

The end user the call acted for (Anlyon-End-User), whose own accounts it used. Null for a call with the workspace's own accounts. erased~<hash> once that end user is erased.

gradestring | null

On invoke responses and single reads: the receipt grade of the effect this invocation created. See Effect.grade. Absent when the invocation has no effect, and on list reads.

Allowed:confirmedacknowledgedunknownfailedrefuseddeniedpendingnull
retryOfstring | nullrequired

The failed invocation this one deliberately retried.

retriedBystring | null

On single reads: the invocation that retried this one.

resolutionobject | null

On single reads: the operator's confirmed outcome for an invocation that was unknown.

Show properties
outcomestringrequired
Allowed:succeededfailed
evidencestringrequired
externalReferencestring | nullrequired
resolvedByobjectrequired
Show properties
typestringrequired
Allowed:api_keyuser
idstringrequired
resolvedAtstring<date-time>required
actionNamestringrequired
actionVersionIdstring | nullrequired

The immutable action version this invocation ran. Lets an audit answer which definition executed a given call rather than inferring it. Null only for invocations recorded before versioning existed.

statusstringrequired

unknown means the request may have reached the destination and Anlyon cannot confirm what happened a timeout, or a socket that died after the request was written. It is deliberately distinct from failed, which means the call did not happen: an error before anything left, such as a blocked URL or an invalid template. Do not retry an unknown invocation automatically. Reconcile it with the destination first; retrying is how one refund becomes two. This value is additive clients that do not know it should treat an unrecognised status as not-successful rather than as failed.

Allowed:pending_approvalrunningsucceededfailedunknowndeniedexpired
responseStatusinteger | nullrequired
min 100 · max 599
bodystring | nullrequired

Redacted and truncated upstream response body.

errorstring | nullrequired
durationMsinteger | nullrequired
min 0
approvalIdstring | nullrequired
decisionInvocationDecision | nullrequired

Why the request was allowed or refused, when a policy, a person or expiry decided it. Persisted on the invocation, so it reads the same after the policy is edited or deleted. Null while undecided, for an invocation that ran with no gate, and on rows recorded before this field existed. For a request that was never sent, responseStatus and body stay null: no response is fabricated.

Show properties
Any of:
InvocationDecision
sourcestringrequired
Allowed:policyhumansystemassistant
codestringrequired
Allowed:POLICY_DENIEDPOLICY_APPROVEDHUMAN_APPROVEDHUMAN_DENIEDAPPROVAL_EXPIREDASSISTANT_APPROVEDEND_USER_ERASED
effectstringrequired

What actually happened to the request.

Allowed:approveddeniedexpired
explanationstringrequired
policyobject | nullrequired

The policy that decided, as it stood at decision time. Null when no policy decided.

Show properties
idstringrequired
namestringrequired
versionintegerrequired
decidedAtstring<date-time>required

Database time the decision was committed.

null
null
createdAtstring<date-time>required
completedAtstring<date-time> | nullrequired
400

Bad Request - Invalid input data

successbooleanrequired
requestIdstringrequired

Correlation ID matching the X-Request-Id response header.

errorobjectrequired
Show properties
codestring
messagestring
detailsobject
fixErrorFix

How to get past this error, for a person or an agent. Present on refusals with a known next step, such as a missing scope or role, a plan or billing limit, a halted environment, or a missing secret, connected account, OAuth app or end-user header. Absent when there is no fix to give. Kept in production responses, unlike details.

Show properties
summarystringrequired

One sentence that says what to do.

commandstring

An exact anlyon CLI command that fixes it. Absent when no command does.

urlstring<uri>

An absolute console link where a person fixes it.

docsstring<uri>

A docs page that explains it.

401

Unauthorized - Invalid or missing API key

successbooleanrequired
requestIdstringrequired

Correlation ID matching the X-Request-Id response header.

errorobjectrequired
Show properties
codestring
messagestring
detailsobject
fixErrorFix

How to get past this error, for a person or an agent. Present on refusals with a known next step, such as a missing scope or role, a plan or billing limit, a halted environment, or a missing secret, connected account, OAuth app or end-user header. Absent when there is no fix to give. Kept in production responses, unlike details.

Show properties
summarystringrequired

One sentence that says what to do.

commandstring

An exact anlyon CLI command that fixes it. Absent when no command does.

urlstring<uri>

An absolute console link where a person fixes it.

docsstring<uri>

A docs page that explains it.

403

Authenticated credential lacks the required scope or workspace access.

successbooleanrequired
requestIdstringrequired

Correlation ID matching the X-Request-Id response header.

errorobjectrequired
Show properties
codestring
messagestring
detailsobject
fixErrorFix

How to get past this error, for a person or an agent. Present on refusals with a known next step, such as a missing scope or role, a plan or billing limit, a halted environment, or a missing secret, connected account, OAuth app or end-user header. Absent when there is no fix to give. Kept in production responses, unlike details.

Show properties
summarystringrequired

One sentence that says what to do.

commandstring

An exact anlyon CLI command that fixes it. Absent when no command does.

urlstring<uri>

An absolute console link where a person fixes it.

docsstring<uri>

A docs page that explains it.

404

Not Found - Resource does not exist

successbooleanrequired
requestIdstringrequired

Correlation ID matching the X-Request-Id response header.

errorobjectrequired
Show properties
codestring
messagestring
detailsobject
fixErrorFix

How to get past this error, for a person or an agent. Present on refusals with a known next step, such as a missing scope or role, a plan or billing limit, a halted environment, or a missing secret, connected account, OAuth app or end-user header. Absent when there is no fix to give. Kept in production responses, unlike details.

Show properties
summarystringrequired

One sentence that says what to do.

commandstring

An exact anlyon CLI command that fixes it. Absent when no command does.

urlstring<uri>

An absolute console link where a person fixes it.

docsstring<uri>

A docs page that explains it.

409

The request conflicts with current resource state or a concurrent decision.

successbooleanrequired
requestIdstringrequired

Correlation ID matching the X-Request-Id response header.

errorobjectrequired
Show properties
codestring
messagestring
detailsobject
fixErrorFix

How to get past this error, for a person or an agent. Present on refusals with a known next step, such as a missing scope or role, a plan or billing limit, a halted environment, or a missing secret, connected account, OAuth app or end-user header. Absent when there is no fix to give. Kept in production responses, unlike details.

Show properties
summarystringrequired

One sentence that says what to do.

commandstring

An exact anlyon CLI command that fixes it. Absent when no command does.

urlstring<uri>

An absolute console link where a person fixes it.

docsstring<uri>

A docs page that explains it.

429

Too Many Requests - Rate limit exceeded. A workspace's API requests are limited per minute and per UTC clock hour by plan; Retry-After says when to try again, and an hourly refusal names the limit and when the count resets. Successful responses carry the same limits in X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset (the minute) and X-RateLimit-Limit-Hour, X-RateLimit-Remaining-Hour, X-RateLimit-Reset-Hour (the hour).

successbooleanrequired
requestIdstringrequired

Correlation ID matching the X-Request-Id response header.

errorobjectrequired
Show properties
codestring
messagestring
detailsobject
fixErrorFix

How to get past this error, for a person or an agent. Present on refusals with a known next step, such as a missing scope or role, a plan or billing limit, a halted environment, or a missing secret, connected account, OAuth app or end-user header. Absent when there is no fix to give. Kept in production responses, unlike details.

Show properties
summarystringrequired

One sentence that says what to do.

commandstring

An exact anlyon CLI command that fixes it. Absent when no command does.

urlstring<uri>

An absolute console link where a person fixes it.

docsstring<uri>

A docs page that explains it.

Try it
Server
Authorization
Parameters
Bodyapplication/json
Request
curl -X POST 'https://api.anlyon.com/api/v2/end-users/string/approvals/string/decide' \
  -H 'Authorization: Bearer YOUR_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{
  "decision": "approve",
  "reason": "string"
}'
Response
{
  "success": true,
  "data": {
    "approval": {
      "id": "apr_01JABCDEF",
      "kind": "action",
      "status": "pending",
      "title": "string",
      "description": "string",
      "payload": {},
      "decisionNote": "string",
      "decidedBy": {
        "type": "api_key",
        "id": "string",
        "displayName": "string"
      },
      "votes": [
        {
          "decision": "approve",
          "decidedBy": {
            "type": "api_key",
            "id": "string",
            "displayName": "string"
          },
          "note": "string",
          "selfApproved": true,
          "decidedAt": "2019-08-24T14:15:22Z"
        }
      ],
      "requiredApprovals": 1,
      "approvedCount": 0,
      "matchedPolicyId": "string",
      "matchedPolicyVersion": 0,
      "policyExplanation": "string",
      "decisionOrigin": "human",
      "endUserId": "string",
      "decider": "team",
      "expiresAt": "2019-08-24T14:15:22Z",
      "decidedAt": "2019-08-24T14:15:22Z",
      "createdAt": "2019-08-24T14:15:22Z",
      "advice": {
        "status": "pending",
        "statusReason": "string",
        "model": "vigil-1",
        "recommendation": "approve",
        "risk": 0,
        "riskLevel": "routine",
        "confidence": 0,
        "reasons": [
          "string"
        ],
        "flags": {
          "injectionSuspected": 0,
          "consistentWithHistory": 0,
          "amountUnusual": 0
        },
        "history": {
          "approved": 0,
          "denied": 0,
          "maxAmount": 0,
          "medianAmount": 0
        },
        "auditRequested": true,
        "auditVerdict": "agree",
        "createdAt": "2019-08-24T14:15:22Z",
        "completedAt": "2019-08-24T14:15:22Z"
      }
    },
    "invocation": {
      "id": "inv_01JABCDEF",
      "effectId": "eff_01JABCDEF",
      "endUserId": "string",
      "grade": "confirmed",
      "retryOf": "string",
      "retriedBy": "string",
      "resolution": {
        "outcome": "succeeded",
        "evidence": "string",
        "externalReference": "string",
        "resolvedBy": {
          "type": "api_key",
          "id": "string"
        },
        "resolvedAt": "2019-08-24T14:15:22Z"
      },
      "actionName": "string",
      "actionVersionId": "acv_01JABCDEF",
      "status": "pending_approval",
      "responseStatus": 100,
      "body": "string",
      "error": "string",
      "durationMs": 0,
      "approvalId": "string",
      "decision": {
        "source": "policy",
        "code": "POLICY_DENIED",
        "effect": "approved",
        "explanation": "Denied by policy \"refund_order_denied\", version 2. The request was not sent.",
        "policy": {
          "id": "apol_01JABCDEF",
          "name": "string",
          "version": 0
        },
        "decidedAt": "2019-08-24T14:15:22Z"
      },
      "createdAt": "2019-08-24T14:15:22Z",
      "completedAt": "2019-08-24T14:15:22Z"
    }
  }
}