Build a waterfall
Start from a template or from scratch, choose steps and speed, set stop rules and per-step limits, test on the sandbox, publish and run.
Before you start
1. Start from a template or from scratch
Templates cover the common jobs (work email, verification, mobile, person and company enrichment,
full lead enrichment). Find one with GET /v1/waterfalls/templates?runnable=true&q=email or in the
dashboard under Waterfalls → Templates, where each card shows whether your vendor keys cover it.
Use template opens it in the builder. From scratch, New waterfall starts with one stage for a
capability and its first three supported endpoints.
2. Steps
A stage runs one capability. Its steps are tried by the speed profile until the stop rule holds:
- A routed step is a pool: the capability's endpoints filtered by
provider preferences (
order,only,ignore,allow_fallbacks), up tomax_endpoints. Templates use routed steps only, so they stay vendor-neutral. - An endpoint step pins one vendor endpoint, such as
hunter/email.find.
To pin vendors on a template, pass pins when creating it: {"pins":{"email":["hunter"]}} puts
those vendors first in that stage's pool, and "pins_only": true turns off the fallback.
Each step can set timeout_ms, retries, max_cost_micro, required fields, a minimum confidence,
verified-only, what a vendor 4xx does, and a when guard ({"field":"email","op":"exists"},
combined with all, any and not). A stage can also have a when: a stage that's skipped
doesn't count against the outcome.
3. Speed, stop rules and budget
| Choice | Options |
|---|---|
| Speed | fastest (race, hedge 750 ms), balanced (one at a time, hedge at 3 s), cheapest (sequential, cheapest first), custom |
| Stop | first_hit, first_verified, until_fields_filled, all_then_merge, condition, combined with stop_mode any or all |
| Budget | max_cost_micro on the definition and on each run; the run stops before an attempt that would pass it and returns the partial record |
POST /v1/waterfalls/estimate prices a definition or a template without calling any vendor:
worst-case and expected cost, expected time and fill, plus every step's quote.
4. Inputs between stages
A stage's input is the run input plus anything earlier stages found. Capability inputs fill
themselves from the golden record by name, so a company stage gets the domain that a person
stage returned. Map one explicitly with input_map: {"domain":"stages.employer.domain"} or
{"email":"input.work_email"}. Mapped values are normalized like run inputs; a website URL
becomes a bare domain, for example. Set fields on a stage to keep only those outputs. See
merge rules.
5. Test
The builder's test runner runs the draft ("version":"draft"). On a grid_test_ key, the
sandbox-* templates and vendors are deterministic and need no vendor key (their calls still draw on
your credit at list price). A scenario input scripts each
sandbox vendor (swift, deep, sure) with hit, miss, unverified, lowconf, timeout,
slow:<ms>, 500, 400 or 429:<s>. For example, swift=miss,deep=slow:2000,sure=hit lets you
check fallbacks and stop rules without spending anything.
6. Publish and run
Publishing freezes a semver version (POST /v1/waterfalls/{id}/versions {"bump":"minor"};
from-template publishes 1.0.0). Then run it:
| Mode | Call |
|---|---|
| Sync | POST /v1/waterfalls/{id}/run {"input":{…}}, up to 50 s |
| Async | add "async": true or Prefer: respond-async, then poll GET /v1/waterfalls/{id}/runs/{run_id}, stream /events, or pass webhook_url |
| Batch | POST /v1/waterfalls/batch-run with up to 1,000 rows or a CSV, then GET /v1/lists/{id} |
| Your endpoint | POST /v1/x/{workspace}/{name}, or the MCP tool x_run |
import { createGrid } from "@relaygrid/sdk";
const grid = createGrid({ apiKey: process.env.GRID_API_KEY! });
const wf = await grid.waterfalls.fromTemplate("full-lead-enrichment", {
pins: { email: ["hunter"] },
max_cost_micro: 200_000,
});
const run = await grid.waterfalls.run(wf.id, { email: "ada@example.com" }, { async: true });
const done = await grid.waterfalls.waitFor(wf.id, run.id);
console.log(done.outcome, done.data, done._provenance);Waterfall templates
Every built-in waterfall template, its inputs, outputs, capabilities, speed, run mode and list-price cost, generated from the template library.
Merge rules
How a waterfall picks each field's value when vendors disagree, records provenance and conflicts, and builds one golden record across stages.