Skip to main content

Approvals

Flow supports optional human review before delivery. When a gate is configured with approvalMode: "manual", validated runs are held for approver decision before proceeding.

Approval Modes

ModeBehavior
auto (default)Runs proceed directly after validation — no human review
manualRuns wait at pending_approval status until an approver approves or rejects

Configuring Approvers

Set up approval when creating or updating a gate:

{
"approvalMode": "manual",
"approvalConfig": {
"approvers": [
{ "type": "internal", "email": "[email protected]" },
{ "type": "external", "email": "[email protected]" }
],
"timeout_hours": 48
}
}

Approver Types

TypeDescription
internalA user with a Rynko account on your team — reviews via the dashboard
externalAny email address — reviews via a magic link sent by email

Decision Logic

Flow uses any-approves logic:

  • The first approval moves the run to approved and triggers delivery immediately
  • The first rejection moves the run to rejected (terminal) — no delivery

Once a decision is made, other approvers cannot override it.


Internal Approvers

Internal approvers review runs directly in the Rynko dashboard.

Dashboard Inbox

curl https://api.rynko.dev/api/flow/approvals \
-H "Authorization: Bearer YOUR_API_KEY"

Returns all pending approvals assigned to the authenticated user.

Making a Decision

# Approve
curl -X POST https://api.rynko.dev/api/flow/approvals/APPROVAL_ID/approve \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "comment": "Looks good, approved." }'

# Reject
curl -X POST https://api.rynko.dev/api/flow/approvals/APPROVAL_ID/reject \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "comment": "Amount exceeds policy limit." }'

The comment field is optional (max 1000 characters).


External approvers receive an email with a magic link that takes them to a review portal — no Rynko account required.

How It Works

  1. A run reaches pending_approval status
  2. Flow sends an email to each external approver with a unique magic link
  3. The approver clicks the link and enters their email as identity verification
  4. They receive a short-lived review token (valid for 2 hours)
  5. They can view the run details and approve or reject

Review Portal Endpoints

These endpoints are public (no API key required) — they use the magic link token for authentication.

Authenticate

curl -X POST https://api.rynko.dev/api/flow/review/authenticate \
-H "Content-Type: application/json" \
-d '{
"token": "MAGIC_LINK_TOKEN",
"email": "[email protected]"
}'

Response:

{
"reviewToken": "eyJ...",
"expiresIn": 7200
}

The email must match the token's intended recipient (identity challenge).

View Inbox

curl https://api.rynko.dev/api/flow/review/inbox \
-H "Authorization: Bearer REVIEW_TOKEN"

View Approval Details

curl https://api.rynko.dev/api/flow/review/approvals/APPROVAL_ID \
-H "Authorization: Bearer REVIEW_TOKEN"

Returns the approval record with full run context (payload, validation results, gate info).

Approve or Reject

# Approve
curl -X POST https://api.rynko.dev/api/flow/review/approvals/APPROVAL_ID/approve \
-H "Authorization: Bearer REVIEW_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "comment": "Approved after review." }'

# Reject
curl -X POST https://api.rynko.dev/api/flow/review/approvals/APPROVAL_ID/reject \
-H "Authorization: Bearer REVIEW_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "comment": "Data does not match requirements." }'

If the approver didn't receive the email or the link expired:

curl -X POST https://api.rynko.dev/api/flow/review/resend \
-H "Content-Type: application/json" \
-d '{
"token": "ORIGINAL_MAGIC_LINK_TOKEN",
"email": "[email protected]"
}'

AI Judge → Approval Routing

AI Judge results can automatically trigger human review in three ways:

Low Confidence

When any criterion's confidence score falls below aiJudgeConfidenceThreshold (default 0.7), the run is automatically routed to human approval — regardless of the gate's normal approval configuration.

On Fail → Review

Set aiJudgeOnFail: "review" on your gate to route AI Judge failures to human approval instead of hard-rejecting. This lets approvers override the AI's judgment:

{
"aiJudgeEnabled": true,
"aiJudgeOnFail": "review",
"approvalMode": "manual",
"approvalConfig": {
"approvers": [
{ "type": "internal", "email": "[email protected]" }
]
}
}

AI Judge Verdict in Approval Expressions

When AI Judge completes, its verdict is injected into the approval condition expression context as aiJudge. This enables sophisticated routing:

// Route to approval whenever AI Judge fails
aiJudge.overall === 'fail'

// Route when any criterion has moderate confidence
aiJudge.criteria.some(c => c.confidence < 0.8)

// Combine with business logic
amount > 10000 || aiJudge.criteria.some(c => c.verdict === 'fail')

Available fields in aiJudge:

FieldTypeDescription
aiJudge.overall'pass' or 'fail'Overall AI Judge verdict
aiJudge.summarystringe.g. "2 of 3 criteria passed"
aiJudge.criteriaarrayPer-criterion results
aiJudge.criteria[].criterionstringThe criterion text
aiJudge.criteria[].verdict'pass' or 'fail'Individual verdict
aiJudge.criteria[].confidencenumber0.0-1.0 confidence score

Timeout

If no approver makes a decision within the configured timeout_hours, the approval expires. Configure the timeout (1-720 hours) in the gate's approvalConfig.


Delivery Configuration for Human-in-the-Loop Workflows

When using manual approval, consider how your application will receive the reviewer's decision.

Production Best Practice: Webhooks

For production human-in-the-loop workflows, configure a webhook delivery channel on the gate. This way, once an approver approves or rejects a run, Flow automatically delivers the result to your endpoint — no polling required.

{
"approvalMode": "manual",
"deliveryChannels": [
{
"type": "webhook",
"url": "https://your-app.com/webhooks/flow",
"secret": "whsec_..."
}
]
}

This eliminates the need to poll the API and reduces latency between the reviewer's decision and your application's reaction.

Without Delivery Channels

If no delivery channels are configured, the run will still move to approved or rejected status after the reviewer decides, but no outbound notification is sent. In this case, you must:

  • Poll the API: Call GET /api/flow/runs/:id periodically to check the run status
  • Use MCP tools: Use the get_run_status MCP tool from an AI agent to check the outcome

This approach works for prototyping and low-volume use cases but is not recommended for production — it adds latency and consumes unnecessary API calls.


Approval Limits by Plan

PlanMax Approvers per Gate
Free5
Starter10
Growth25
ScaleUnlimited