Guides
Flows (automation)
A flow is a versioned list of steps: send a template, wait for it to be signed, ask a colleague to approve, wait three days, notify your CRM. Runs execute in the background and branch on step outcomes.
Steps#
| Type | Kind | Outcomes | Config |
|---|---|---|---|
send_template | await | signed, rejected, expired, cancelled | template_id, title, recipients (1-20: email, name, phone, contact_id, role), verification, expires_in_days (1-365) |
send_package | await | same as above | package_id, title, variables, signers, signing_order, verification, expires_in_days, mode (send or drafts) |
internal_approval | await | approved, rejected | Either approver_user_id or approver_role (ORG_ADMIN, TEAM_ADMIN, TEAM_MANAGER), message |
wait | wait | done | days/hours/minutes, or until_variable |
notify | fire | done | channel (email or webhook), to (owner, user, address, recipients), user_id, address, recipients_of, subject, message |
set_variable | inline | done | name, value |
Each step has a unique key, optional label, its config, an optional when condition (step + outcome_in, or var + equals) and optional paths per outcome with their own steps and a then of continue, stop, fail or goto. Up to 100 steps per flow. GET /flows/step-types returns the step catalog with config schemas, and POST /flows/validate checks a step list without saving it.
A notify step with channel: "webhook" emits a flow.step event to your webhooks.
Triggers#
manualandapi: runs are started explicitly withPOST /flows/{flow_id}/runs.document_completed_of_template: a run starts when a document created fromtrigger_template_idcompletes.
Lifecycle#
POST /flowscreates a flow (name,description,trigger,steps, optionalteam_id,active). Edits withPATCH /flows/{id}change the draft steps.POST /flows/{id}/dry-runsimulates a run with givenvariablesand assumedoutcomes, returning the path and actions without side effects.POST /flows/{id}/publishpublishes the current steps as a new version. Runs always use the published version (409 flow_not_publishedotherwise).POST /flows/{id}/runswith{"variables": {...}}(up to 100) starts a run (201).- Watch runs with
GET /flow-runs(flow_id,status,limit1-200) andGET /flow-runs/{run_id}(steps, variables, outcomes, documents, event history). Statuses:running,waiting,completed,failed,cancelled. - Decide approvals with
POST /flow-runs/{run_id}/approvals/{step_key}({"decision": "approve"}or"reject", optionalcomment), and stop a run withPOST /flow-runs/{run_id}/cancel.
Example#
Send a lease from a template, then notify your system by webhook when it is signed, or email the owner when it is not.
FLOW_ID=$(curl -sS -X POST "https://api.sign.yt/v1/flows" \
-H "Authorization: Bearer $SIGNYT_API_KEY" -H "Content-Type: application/json" \
-d '{
"name": "Lease onboarding",
"trigger": "api",
"steps": [
{"key": "lease", "type": "send_template",
"config": {"template_id": "'"$TEMPLATE_ID"'", "title": "Lease - {{client_name}}",
"recipients": [{"email": "{{client_email}}", "name": "{{client_name}}"}]},
"paths": {
"signed": {"steps": [
{"key": "notify_crm", "type": "notify",
"config": {"channel": "webhook", "subject": "Lease signed: {{client_name}}"}}
], "then": "continue"},
"rejected": {"steps": [
{"key": "tell_owner", "type": "notify",
"config": {"channel": "email", "to": "owner", "subject": "Lease declined by {{client_name}}"}}
], "then": "stop"}
}}
]
}' | jq -r .id)
curl -sS -X POST "https://api.sign.yt/v1/flows/$FLOW_ID/publish" -H "Authorization: Bearer $SIGNYT_API_KEY"
curl -sS -X POST "https://api.sign.yt/v1/flows/$FLOW_ID/runs" \
-H "Authorization: Bearer $SIGNYT_API_KEY" -H "Content-Type: application/json" \
-H "Idempotency-Key: lease-run-anna-nowak" \
-d '{"variables": {"client_name": "Anna Nowak", "client_email": "[email protected]"}}'import os
import httpx
http = httpx.Client(
base_url="https://api.sign.yt/v1",
headers={"Authorization": f"Bearer {os.environ['SIGNYT_API_KEY']}"},
)
steps = [{
"key": "lease", "type": "send_template",
"config": {"template_id": os.environ["TEMPLATE_ID"], "title": "Lease - {{client_name}}",
"recipients": [{"email": "{{client_email}}", "name": "{{client_name}}"}]},
"paths": {"signed": {"steps": [{"key": "notify_crm", "type": "notify",
"config": {"channel": "webhook", "subject": "Lease signed: {{client_name}}"}}],
"then": "continue"}},
}]
check = http.post("/flows/validate", json={"steps": steps}).json()
assert check["valid"], check["errors"]
flow = http.post("/flows", json={"name": "Lease onboarding", "trigger": "api", "steps": steps}).raise_for_status().json()
http.post(f"/flows/{flow['id']}/publish").raise_for_status()
run = http.post(
f"/flows/{flow['id']}/runs",
json={"variables": {"client_name": "Anna Nowak", "client_email": "[email protected]"}},
headers={"Idempotency-Key": "lease-run-anna-nowak"},
).raise_for_status().json()
print(run["id"], run["status"])const base = "https://api.sign.yt/v1";
const headers = { Authorization: `Bearer ${process.env.SIGNYT_API_KEY}`, "Content-Type": "application/json" };
const post = async (path: string, body?: unknown, extra: Record<string, string> = {}) => {
const res = await fetch(base + path, { method: "POST", headers: { ...headers, ...extra }, body: body ? JSON.stringify(body) : undefined });
if (!res.ok) throw new Error(`${path}: HTTP ${res.status} ${await res.text()}`);
return res.json();
};
const flow = await post("/flows", {
name: "Lease onboarding",
trigger: "api",
steps: [{
key: "lease", type: "send_template",
config: { template_id: process.env.TEMPLATE_ID, title: "Lease - {{client_name}}",
recipients: [{ email: "{{client_email}}", name: "{{client_name}}" }] },
paths: { signed: { steps: [{ key: "notify_crm", type: "notify",
config: { channel: "webhook", subject: "Lease signed: {{client_name}}" } }],
then: "continue" } },
}],
});
await post(`/flows/${flow.id}/publish`);
const run = await post(`/flows/${flow.id}/runs`,
{ variables: { client_name: "Anna Nowak", client_email: "[email protected]" } },
{ "Idempotency-Key": "lease-run-anna-nowak" });
console.log(run.id, run.status);Validate templates and placeholders against GET /flows/step-types and POST /flows/validate before publishing; validation errors are returned per step.