Schema & Field
Schema classes define the structure of workflow inputs and outputs. They map directly to JSON Schema objects used by the Tray.io platform.
Schema class
Section titled “Schema class”Subclass Schema and declare fields with Python type annotations:
from riffle.sdk import Schema
class ContactInput(Schema): name: str email: str age: int active: boolThis corresponds to a JSON Schema with type: "object" and four properties.
Nested schemas
Section titled “Nested schemas”When a field contains a nested object with its own properties, Riffle emits a separate Schema class and uses it as the type annotation:
class Address(Schema): street: str city: str zip_code: str
class ContactInput(Schema): name: str address: AddressFor arrays of objects, use list[ClassName]:
class LineItem(Schema): product: str quantity: int
class Order(Schema): items: list[LineItem]The inner Meta class holds schema-level properties that don’t map to individual fields:
class ContactInput(Schema): name: str email: str
class Meta: schema = "http://json-schema.org/draft-04/schema#" required = ["name", "email"] additional_properties = False advanced = ["email"]| Attribute | Type | Description |
|---|---|---|
schema | str | JSON Schema version URI |
required | list[str] | Field names that must be present |
additional_properties | bool | Whether unlisted fields are allowed |
advanced | list[str] | Fields marked as advanced in the Tray.io UI |
All Meta attributes are optional. Omit Meta entirely if you don’t need any of them.
Field()
Section titled “Field()”When a field carries metadata beyond its type, use the Field() descriptor:
from riffle.sdk import Field, Schema
class InvoiceInput(Schema): amount: float = Field(title="Invoice Amount", description="Total in USD") due_date: str = Field(format="date-time", date_mask="DD/MM/YYYY") tags: list[str] = Field(items_title="Tag") content_type: str = Field(name="content-type")Plain annotations (name: str) work when no extra metadata is needed. Field() is only required when you need to set one or more of the parameters below.
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
title | str | Display name shown in the Tray.io workflow builder UI. Different from the Python field name — title is a human-readable label. |
description | str | Help text shown in the Tray.io UI for this field. |
default | any | Default value for the field. |
format | str | JSON Schema format hint (e.g. "date-time", "uri", "email"). |
date_mask | str | Date format mask (e.g. "DD/MM/YYYY"). Platform-specific. |
types | list[str] | Union type list for polymorphic fields (e.g. ["string", "integer"]). Used when a field accepts multiple JSON Schema types. |
additional_items | bool | Whether additional array items beyond the schema are allowed. |
items_title | str | Display title for items inside an array field. When a field is list[str], title labels the array itself while items_title labels each element within it. |
name | str | Original JSON field name when it differs from the Python identifier. Riffle sets this automatically for fields with characters that aren’t valid in Python identifiers (e.g. hyphens). You generally don’t need to set this manually. |
additional_properties | bool | dict | Whether additional properties are allowed on an unstructured object field. Only applies to dict fields without nested schema classes. |
required | list[str] | Required sub-field names on an unstructured object field. Only applies to dict fields without nested schema classes. |
advanced | list[str] | Advanced sub-field markers on an unstructured object field. Only applies to dict fields without nested schema classes. |
title vs items_title
Section titled “title vs items_title”These two parameters serve different purposes on array fields:
class Config(Schema): recipients: list[str] = Field( title="Email Recipients", items_title="Email Address", )titlelabels the field itself — in the Tray.io UI, the array input as a whole is called “Email Recipients”.items_titlelabels each individual element within the array — when a user adds an entry, it’s labeled “Email Address”.
For non-array fields, items_title has no effect.
The name parameter preserves JSON field names that can’t be expressed as Python identifiers:
class Headers(Schema): content_type: str = Field(name="content-type") x_request_id: str = Field(name="x-request-id") accept: str # no Field() needed — valid Python identifier matches JSON nameRiffle generates Field(name=...) automatically during riffle pull. You shouldn’t need to set it manually unless you’re writing a workflow from scratch with field names that contain hyphens or other special characters.