Gates
A gate is a named validation checkpoint. It defines what data structure you expect, what business rules must hold, and what happens after validation succeeds (rendering, approval, delivery).
Gate Identifiers
Every gate has three identifiers you can use interchangeably in API calls:
| Type | Format | Example |
|---|---|---|
| UUID | 36 characters | 550e8400-e29b-41d4-a716-446655440000 |
| shortId | fgate_ + 8 chars | fgate_a1b2c3d4 |
| slug | lowercase + hyphens | order-validation |
The slug is auto-generated from the gate name and is unique within your workspace.
Schema Definition
Gate schemas use an object format to define expected fields:
{
"type": "object",
"properties": {
"customerName": { "type": "string", "required": true },
"email": { "type": "string", "required": true, "format": "email" },
"amount": { "type": "number", "required": true, "min": 0 },
"isPriority": { "type": "boolean", "required": false },
"orderDate": { "type": "date", "required": true },
"tags": { "type": "array", "itemType": "string" },
"address": {
"type": "object",
"properties": {
"street": { "type": "string", "required": true },
"city": { "type": "string", "required": true },
"zip": { "type": "string", "required": true }
}
}
}
}
Supported Types
| Type | Description | Constraints |
|---|---|---|
string | Text value | minLength, maxLength, format, allowedValues |
number | Numeric value | min, max |
boolean | True/false | — |
date | Date string | — |
array | List of items | itemType (required) |
object | Nested object | properties (required) |
String Formats
The format constraint validates string patterns:
| Format | Validates |
|---|---|
email | Email address |
url | URL |
Allowed Values
Restrict a field to a set of valid options:
{
"status": {
"type": "string",
"required": true,
"allowedValues": ["pending", "active", "completed", "cancelled"]
}
}
Import from Template
If you have an existing Rynko document template, you can import its variables as a gate schema:
curl -X POST https://api.rynko.dev/api/flow/gates/ORDER_GATE_ID/import-schema \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "templateId": "invoice-template" }'
This copies the template's variable definitions into the gate schema and sets the gate's validation mode to variables.
Import from Pydantic or Zod
If your validation logic already lives in a Pydantic model (Python) or a Zod schema (TypeScript), you can paste its JSON Schema output directly into the gate — no need to rebuild the schema from scratch.
Generate the JSON Schema output
- Pydantic (Python)
- Zod (TypeScript)
import json
from pydantic import BaseModel
from typing import Optional
from datetime import date
class OrderModel(BaseModel):
customer_name: str
email: str
amount: float
quantity: int
order_date: date
notes: Optional[str] = None
# Pydantic v2
print(json.dumps(OrderModel.model_json_schema(), indent=2))
# Pydantic v1
# print(json.dumps(OrderModel.schema(), indent=2))
Install zod-to-json-schema first:
npm install zod-to-json-schema
import { z } from 'zod';
import { zodToJsonSchema } from 'zod-to-json-schema';
const OrderSchema = z.object({
customerName: z.string(),
email: z.string().email(),
amount: z.number().positive(),
quantity: z.number().int().min(1),
orderDate: z.string().date(),
notes: z.string().optional(),
});
console.log(JSON.stringify(zodToJsonSchema(OrderSchema), null, 2));
Copy the printed JSON output to your clipboard.
Import in the dashboard
- Open your gate and click Schema & Validate.
- Click Import from Pydantic / Zod.
- Select the Pydantic or Zod tab.
- Paste the JSON output into the text area.
- Click Parse Schema to preview what will be imported.
- Review any warnings, then click Import.
The import replaces the existing schema and merges any generated business rules into your existing ones (existing rules are preserved).
What gets imported
| Schema feature | Imported as |
|---|---|
| Object properties | Gate schema properties with mapped types |
required fields | required: true on each property |
minimum / maximum | min / max constraints |
minLength / maxLength | String length constraints |
pattern | Regex pattern constraint |
enum / const | allowedValues constraint |
default | Default value constraint |
format: date or date-time | date type |
format: email | String with email format |
integer type | number type + multipleOf: 1 constraint |
Nested $ref objects | Nested object properties (resolved recursively) |
anyOf / oneOf with a null variant | Nullable field (required: false) |
if / then / else | Business rule (where convertible) |
uniqueItems: true on an array | Business rule checking array uniqueness |
not constraint | Business rule (where convertible) |
Understanding import warnings
Any part of the schema that could not be converted automatically produces a warning. Warnings are shown immediately after parsing — review each one and resolve it in the Schema Editor or Business Rules section before saving.
| Warning type | What happened | What to do |
|---|---|---|
| union type | The field is a union of multiple incompatible types (e.g. Union[A, B, C]). Only the first type was imported. | Open the Schema Editor and correct the field type, or split it into separate fields. |
| allOf merge conflict | Two allOf schemas defined conflicting values for the same key. The last value was used. | Verify the field's settings in the Schema Editor. |
| depth limit | The model exceeds 15 levels of nesting. Properties beyond that were not imported. | Add the missing nested fields manually in the Schema Editor. |
| not | A not constraint is too complex to auto-convert. It was skipped. | Add a Business Rule manually using !(expression) syntax. |
| if/then/else skipped | A conditional rule's condition uses unsupported patterns. The rule was skipped entirely. | Add a Business Rule manually to replicate the logic. |
| if/then/else truncated | A generated conditional rule exceeded the 450-character expression limit and was truncated. | Open Business Rules, find the affected rule, and shorten or rewrite it. |
After importing, click Edit Schema to review all properties, then expand Business Rules to check any auto-generated rules. Don't activate the gate until all warnings are resolved.
Limits
$refreferences are resolved recursively; circular references are safely treated as plainobject.- Maximum nesting depth: 15 levels.
- Maximum business rules per gate: 20. If the import would push you over this limit, remove some existing rules first or reduce the rules in the imported schema.
Business Rules
Business rules are cross-field expressions that enforce domain logic beyond simple type checking.
Rule Structure
{
"businessRules": [
{
"id": "rule_date_order",
"name": "End date after start date",
"expression": "endDate > startDate",
"errorMessage": "End date must be after start date",
"enabled": true
},
{
"id": "rule_total_check",
"name": "Line items match total",
"expression": "quantity * unitPrice == totalAmount",
"errorMessage": "Total amount does not match quantity * unit price",
"enabled": true
}
]
}
Expression Syntax
Expressions have access to all payload fields as variables. Supported operations:
| Category | Examples |
|---|---|
| Comparison | >, <, >=, <=, ==, != |
| Logical | &&, ||, ! |
| Arithmetic | +, -, *, /, % |
| Math functions | round(), max(), min(), abs(), pow() |
| String access | Field values are available directly by name |
A rule passes when its expression evaluates to a truthy value. All enabled rules are evaluated independently (no short-circuit) — you'll see all failures at once.
Limits
- Maximum 20 business rules per gate
- Expression maximum length: 500 characters
- Expressions are security-validated at save time (no
eval,require, or prototype access)
Validation Modes
Variables Mode (default)
Validates a JSON object against the schema. This is the standard mode for structured payloads.
Freetext Mode
Validates unstructured text content (articles, reports, code snippets). Configure with:
{
"validationMode": "freetext",
"freetextConfig": {
"contentFormat": "markdown",
"max_content_length": 50000
}
}
| Content Format | Description |
|---|---|
plaintext | Plain text |
markdown | Markdown formatted |
html | HTML content |
code | Source code (set codeLanguage for syntax context) |
In freetext mode, business rules are not evaluated.
Gate Configuration
Approval
Enable human review before delivery:
{
"approvalMode": "manual",
"approvalConfig": {
"approvers": [
{ "type": "internal", "email": "reviewer@company.com" },
{ "type": "external", "email": "client@partner.com" }
],
"timeout_hours": 48
}
}
auto(default) — runs proceed directly after validationmanual— runs wait for an approver to approve or reject
See Approvals for details on the review workflow.
Delivery
Forward validated (and approved) payloads to external systems:
{
"deliveryChannels": [
{
"type": "webhook",
"config": {
"url": "https://api.yourapp.com/webhook",
"headers": { "X-Custom-Header": "value" }
}
}
]
}
Webhook deliveries include an HMAC-SHA256 signature in the X-Rynko-Signature header for verification. Failed deliveries are retried up to 3 times with exponential backoff.
Rendering
Optionally render a document from the validated payload:
{
"renderMode": "rynko",
"renderTemplateId": "invoice-template",
"renderConfig": { "format": "pdf" }
}
| Render Mode | Description |
|---|---|
none (default) | No rendering — validation only |
rynko | Render a Rynko document template using the payload as variables |
custom_api | Forward to a custom rendering API |
Rate Limiting
Throttle submissions per gate:
{
"maxSubmissionsPerMinute": 60
}
When the limit is exceeded, the API returns HTTP 429 with a retryAfter value in seconds.
Circuit Breaker
Automatically pause a gate when failures spike:
{
"circuitBreakerEnabled": true,
"maxFailures": 5,
"cooldownSeconds": 300
}
After maxFailures consecutive failures, the circuit opens and rejects new submissions for cooldownSeconds. This prevents cascading failures.
Notifications
Control how you're notified about gate activity:
{
"notificationMode": "digest",
"notificationDigestMinutes": 5
}
| Mode | Behavior |
|---|---|
immediate | Notify on every event |
digest (default) | Batch notifications every N minutes |
Gate Status
| Status | Description |
|---|---|
active | Accepting submissions (default) |
paused | Rejecting new submissions |
archived | Soft-deleted, not visible in listings |
Update a gate's status:
curl -X PUT https://api.rynko.dev/api/flow/gates/GATE_ID \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "status": "paused" }'
Schema Versioning
Every schema update creates a new version. Each run records the schema version it was validated against. List versions:
curl https://api.rynko.dev/api/flow/gates/GATE_ID/versions \
-H "Authorization: Bearer YOUR_API_KEY"
This lets you track how your validation requirements have evolved and correlate runs with the schema version they used.