Skip to main content

Verification

Always Verify Agent Outputs

AI agents can skip, ignore, or bypass validation. Never trust agent-delivered data without verification. The validation_id is the only proof that data passed through a Rynko gate.

Why Verification Matters​

When an AI agent validates data through Rynko Flow, the typical flow is:

Agent generates data → Agent calls Rynko → Rynko validates → Agent receives result → Agent delivers to your system

The problem: the agent is in control. After receiving a validation failure, the agent can:

  • Ignore the failure and deliver the unvalidated data anyway
  • Modify the validated data before delivering it
  • Skip the validation call entirely

Verification closes this gap. Your receiving system independently confirms with Rynko that the data it received was actually validated and hasn't been tampered with.

Agent delivers data + validation_id → Your system asks Rynko: "Is this legit?" → Rynko confirms or rejects

How It Works​

Every successful validation returns a validation_id — an HMAC-SHA256 signature derived from the payload content:

{
"success": true,
"status": "validated",
"validation_id": "val_4f546e9bcb76f120c4984d72",
"validated_payload": { ... }
}

This ID is:

  • Deterministic — the same payload always produces the same ID
  • Tamper-proof — if any field changes, the ID won't match
  • Signed server-side — only Rynko can generate a valid ID (HMAC secret is never exposed)

Standard Integration Pattern​

This is the recommended pattern for any system that receives data from an AI agent.

Step 1: Agent validates and delivers​

The agent calls a Rynko gate, gets the validated payload and validation_id, and passes both to your system:

{
"validation_id": "val_4f546e9bcb76f120c4984d72",
"data": {
"orderId": "ORD-2026-042",
"amount": 1250.00,
"currency": "USD"
}
}

Step 2: Your system verifies before accepting​

Before processing the data, your system calls Rynko's verify endpoint:

curl -X POST https://api.rynko.dev/api/flow/verify \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"validation_id": "val_4f546e9bcb76f120c4984d72",
"payload": {
"orderId": "ORD-2026-042",
"amount": 1250.00,
"currency": "USD"
}
}'

Verify Response​

Verified:

{
"verified": true,
"runId": "550e8400-e29b-41d4-a716-446655440000",
"gateName": "Order Validation",
"gateSlug": "order-validation"
}

Failed — payload was tampered with:

{
"verified": false,
"runId": "550e8400-e29b-41d4-a716-446655440000",
"gateName": "Order Validation",
"gateSlug": "order-validation"
}

Failed — no matching validation found:

{
"verified": false
}

MCP Verification​

When agents connect via MCP, the same pattern applies. The verify_validation tool is available as a static MCP tool:

Agent calls: validate_order_validation({ orderId: "ORD-042", amount: 1250 })
→ Returns: { validated: true, validation_id: "val_abc123..." }

Downstream system calls: verify_validation({ validation_id: "val_abc123...", payload: {...} })
→ Returns: { verified: true }

The downstream system can call verify_validation via MCP or via the REST API — both use the same verification logic.


Enforcement Levels​

Different applications need different levels of trust. Choose the level that matches your risk:

LevelHow It WorksSecurityFriction
Level 1: Audit onlyAgent validates via MCP. Rynko logs everything. Bypass is detectable but not prevented.LowNone
Level 2: Verify at destinationReceiving system calls /flow/verify before accepting data. Rejects unverified payloads.Medium (recommended)One API call
Level 3: Rynko deliversGate has a delivery webhook. Rynko pushes validated data directly. Agent never touches the destination.HighConfigure webhook URL

Level 2 is the recommended default — it adds one API call to your receiving code and catches both bypass and tampering.


Common Integration Examples​

Express.js Middleware​

Add verification as middleware to any endpoint that receives agent data:

function requireRynkoVerification(req, res, next) {
const { validation_id } = req.body;

if (!validation_id) {
return res.status(403).json({
error: 'Missing validation_id — data must be validated by Rynko before acceptance',
});
}

fetch('https://api.rynko.dev/api/flow/verify', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.RYNKO_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
validation_id,
payload: req.body.data || req.body.payload,
}),
})
.then(r => r.json())
.then(result => {
if (!result.verified) {
return res.status(403).json({ error: 'Rynko verification failed — payload rejected' });
}
req.rynkoVerification = result;
next();
})
.catch(() => res.status(502).json({ error: 'Rynko verification unavailable' }));
}

// Usage:
app.post('/api/orders', requireRynkoVerification, (req, res) => {
// req.rynkoVerification.gateName, req.rynkoVerification.runId available
createOrder(req.body.data);
res.json({ success: true });
});

FastAPI Dependency​

from fastapi import Depends, HTTPException, Request
import httpx

RYNKO_API_KEY = "YOUR_API_KEY"

async def require_rynko_verification(request: Request):
body = await request.json()
validation_id = body.get("validation_id")

if not validation_id:
raise HTTPException(403, "Missing validation_id")

async with httpx.AsyncClient() as client:
result = await client.post(
"https://api.rynko.dev/api/flow/verify",
headers={"Authorization": f"Bearer {RYNKO_API_KEY}"},
json={
"validation_id": validation_id,
"payload": body.get("data") or body.get("payload"),
},
)

if not result.json().get("verified"):
raise HTTPException(403, "Rynko verification failed")

return result.json()


@app.post("/api/orders")
async def create_order(request: Request, verification=Depends(require_rynko_verification)):
body = await request.json()
# verification["gateName"], verification["runId"] available
return process_order(body["data"])

Database Write Guard​

If your agent writes directly to a database, add a verification check in the data access layer:

async function insertValidatedRecord(table, data, validationId) {
// Verify with Rynko before any database write
const verification = await verifyWithRynko(validationId, data);

if (!verification.verified) {
throw new Error(
`Rejected: data for ${table} failed Rynko verification. ` +
`Run ID: ${verification.runId || 'unknown'}`
);
}

// Verified — safe to write
await db.insert(table, {
...data,
_rynko_run_id: verification.runId, // Audit trail
_rynko_gate: verification.gateSlug, // Which gate validated this
_rynko_verified_at: new Date().toISOString(),
});
}

Agent Instructions​

To ensure agents pass the validation_id to downstream systems, include this in your agent's system prompt or MCP tool descriptions:

IMPORTANT: After validating data with Rynko Flow, you MUST pass both the
validated_payload AND the validation_id to any downstream system. The
receiving system will verify the validation_id with Rynko before accepting
the data. Do not modify the validated_payload after validation — any
changes will cause verification to fail.

Frequently Asked Questions​

What if my agent doesn't pass the validation_id?​

Your receiving system should reject the request. The requireRynkoVerification middleware examples above return 403 Forbidden when validation_id is missing. This forces the agent to include it.

What if the agent modifies the payload after validation?​

Verification will fail. The validation_id is an HMAC of the exact validated payload. Even changing a single character causes a mismatch.

Does verification cost a run?​

No. Verification is a read-only operation — it does not create a run or consume quota.

Can I verify the same payload multiple times?​

Yes. Verification is idempotent. You can verify the same validation_id + payload combination as many times as needed.

What about offline or batch scenarios?​

For batch processing, verify each record individually. The verify endpoint is lightweight (~5ms) and can handle high throughput. For fully offline scenarios where you cannot call the API, consider Level 3 (webhook delivery) where Rynko delivers validated data directly to your system.

How long is a validation_id valid?​

As long as the run exists in the system. Run retention follows your subscription tier's data retention policy.