from retab import Retab
client = Retab()
experiment = client.workflows.experiments.create(
workflow_id="wf_abc123",
block_id="extract-invoice",
name="Q1 invoices",
document_captures=[
{"run_id": "wfrun_1"},
{"run_id": "wfrun_2", "step_id": "for_each-0"},
],
n_consensus=5,
)
print(experiment.id)
import { Retab } from "@retab/node";
const client = new Retab({ apiKey: process.env.RETAB_API_KEY });
const experiment = await client.workflows.experiments.create("wf_abc123", "extract-invoice", [
{ runId: "wfrun_1" },
{ runId: "wfrun_2", stepId: "for_each-0" },
], undefined, 5, "Q1 invoices");
console.log(experiment.id);
package main
import (
"context"
"fmt"
"log"
retab "github.com/retab-dev/retab/clients/go"
)
func ptr[T any](v T) *T { return &v }
func main() {
ctx := context.Background()
client, err := retab.NewClient("")
if err != nil {
log.Fatal(err)
}
experiment, err := client.Workflows.Experiments.Create(ctx, &retab.WorkflowExperimentsCreateParams{
WorkflowID: "wf_abc123",
BlockID: ptr("extract-invoice"),
Name: ptr("Q1 invoices"),
DocumentCaptures: []*retab.ExperimentDocumentCaptureRequest{
{RunID: "wfrun_1"},
{RunID: "wfrun_2", StepID: ptr("for_each-0")},
},
NConsensus: ptr(retab.CreateExperimentRequestNConsensus5),
})
if err != nil {
log.Fatal(err)
}
fmt.Println(experiment.ID)
}
require 'retab'
client = Retab::Client.new(api_key: ENV['RETAB_API_KEY'])
experiment = client.workflows.experiments.create(
workflow_id: 'wf_abc123',
block_id: 'extract-invoice',
name: 'Q1 invoices',
document_captures: [
{ run_id: 'wfrun_1' },
{ run_id: 'wfrun_2', step_id: 'for_each-0' },
],
n_consensus: 5,
)
puts experiment.id
use retab::enums::CreateExperimentRequestNConsensus;
use retab::models::{CreateExperimentRequest, ExperimentDocumentCaptureRequest};
use retab::resources::workflow_experiments::CreateParams;
use retab::Retab;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = Retab::new(std::env::var("RETAB_API_KEY")?);
let mut body = CreateExperimentRequest::new("wf_abc123");
body.block_id = Some("extract-invoice".into());
body.name = Some("Q1 invoices".into());
body.document_captures = Some(vec![
ExperimentDocumentCaptureRequest::new("wfrun_1"),
ExperimentDocumentCaptureRequest {
run_id: "wfrun_2".into(),
step_id: Some("for_each-0".into()),
},
]);
body.n_consensus = Some(CreateExperimentRequestNConsensus::V5);
let experiment = client
.workflows().experiments()
.create(CreateParams::new(body))
.await?;
println!("{}", experiment.id);
Ok(())
}
<?php
require 'vendor/autoload.php';
use Retab\Client;
$client = new Client(apiKey: getenv('RETAB_API_KEY'));
$result = $client->workflows()->experiments()->create(
workflowId: 'wf_abc123',
);
print_r($result);
using Retab;
using RetabClient = Retab.Retab;
var apiKey = Environment.GetEnvironmentVariable("RETAB_API_KEY")!;
var client = new RetabClient(apiKey);
var result = await client.Workflows.Experiments.CreateAsync(new WorkflowExperimentsCreateOptions());
Console.WriteLine(result);
import com.retab.RetabClient;
public final class Example {
public static void main(String[] args) throws Exception {
RetabClient client = new RetabClient(System.getenv("RETAB_API_KEY"));
var result = client.workflows().experiments().create("wf_abc123", "block_abc123", null, null, null, "Invoice Processing", null);
System.out.println(result);
}
}
curl -X 'POST' \
'https://api.retab.com/v1/workflows/experiments' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <your-api-key>' \
-d '{
"workflow_id": "wf_abc123",
"block_id": "extract-invoice",
"name": "Q1 invoices",
"document_captures": [
{ "run_id": "wfrun_1" },
{ "run_id": "wfrun_2", "step_id": "for_each-0" }
],
"n_consensus": 5
}'
{
"id": "exp_abc",
"workflow_id": "wf_abc123",
"block_id": "extract-invoice",
"block_kind": "extract",
"n_consensus": 5,
"document_count": 2,
"name": "Q1 invoices",
"last_run_id": null,
"status": "draft",
"score": null,
"is_stale": false,
"schema_drift": "unknown",
"schema_drift_detail": null,
"created_at": "2026-05-01T14:30:00Z",
"updated_at": "2026-05-01T14:30:00Z"
}
{
"detail": "Provide at least one document or document capture."
}
{
"detail": "Block not found: extract-invoice"
}
Experiments
Create Experiment
Create an experiment.
When source_experiment_id is set, duplicates the source experiment
(block, name + “(Copy)”, n_consensus, documents) and rejects any other
field. Otherwise creates a fresh experiment from the provided fields.
POST
/
v1
/
workflows
/
experiments
from retab import Retab
client = Retab()
experiment = client.workflows.experiments.create(
workflow_id="wf_abc123",
block_id="extract-invoice",
name="Q1 invoices",
document_captures=[
{"run_id": "wfrun_1"},
{"run_id": "wfrun_2", "step_id": "for_each-0"},
],
n_consensus=5,
)
print(experiment.id)
import { Retab } from "@retab/node";
const client = new Retab({ apiKey: process.env.RETAB_API_KEY });
const experiment = await client.workflows.experiments.create("wf_abc123", "extract-invoice", [
{ runId: "wfrun_1" },
{ runId: "wfrun_2", stepId: "for_each-0" },
], undefined, 5, "Q1 invoices");
console.log(experiment.id);
package main
import (
"context"
"fmt"
"log"
retab "github.com/retab-dev/retab/clients/go"
)
func ptr[T any](v T) *T { return &v }
func main() {
ctx := context.Background()
client, err := retab.NewClient("")
if err != nil {
log.Fatal(err)
}
experiment, err := client.Workflows.Experiments.Create(ctx, &retab.WorkflowExperimentsCreateParams{
WorkflowID: "wf_abc123",
BlockID: ptr("extract-invoice"),
Name: ptr("Q1 invoices"),
DocumentCaptures: []*retab.ExperimentDocumentCaptureRequest{
{RunID: "wfrun_1"},
{RunID: "wfrun_2", StepID: ptr("for_each-0")},
},
NConsensus: ptr(retab.CreateExperimentRequestNConsensus5),
})
if err != nil {
log.Fatal(err)
}
fmt.Println(experiment.ID)
}
require 'retab'
client = Retab::Client.new(api_key: ENV['RETAB_API_KEY'])
experiment = client.workflows.experiments.create(
workflow_id: 'wf_abc123',
block_id: 'extract-invoice',
name: 'Q1 invoices',
document_captures: [
{ run_id: 'wfrun_1' },
{ run_id: 'wfrun_2', step_id: 'for_each-0' },
],
n_consensus: 5,
)
puts experiment.id
use retab::enums::CreateExperimentRequestNConsensus;
use retab::models::{CreateExperimentRequest, ExperimentDocumentCaptureRequest};
use retab::resources::workflow_experiments::CreateParams;
use retab::Retab;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = Retab::new(std::env::var("RETAB_API_KEY")?);
let mut body = CreateExperimentRequest::new("wf_abc123");
body.block_id = Some("extract-invoice".into());
body.name = Some("Q1 invoices".into());
body.document_captures = Some(vec![
ExperimentDocumentCaptureRequest::new("wfrun_1"),
ExperimentDocumentCaptureRequest {
run_id: "wfrun_2".into(),
step_id: Some("for_each-0".into()),
},
]);
body.n_consensus = Some(CreateExperimentRequestNConsensus::V5);
let experiment = client
.workflows().experiments()
.create(CreateParams::new(body))
.await?;
println!("{}", experiment.id);
Ok(())
}
<?php
require 'vendor/autoload.php';
use Retab\Client;
$client = new Client(apiKey: getenv('RETAB_API_KEY'));
$result = $client->workflows()->experiments()->create(
workflowId: 'wf_abc123',
);
print_r($result);
using Retab;
using RetabClient = Retab.Retab;
var apiKey = Environment.GetEnvironmentVariable("RETAB_API_KEY")!;
var client = new RetabClient(apiKey);
var result = await client.Workflows.Experiments.CreateAsync(new WorkflowExperimentsCreateOptions());
Console.WriteLine(result);
import com.retab.RetabClient;
public final class Example {
public static void main(String[] args) throws Exception {
RetabClient client = new RetabClient(System.getenv("RETAB_API_KEY"));
var result = client.workflows().experiments().create("wf_abc123", "block_abc123", null, null, null, "Invoice Processing", null);
System.out.println(result);
}
}
curl -X 'POST' \
'https://api.retab.com/v1/workflows/experiments' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <your-api-key>' \
-d '{
"workflow_id": "wf_abc123",
"block_id": "extract-invoice",
"name": "Q1 invoices",
"document_captures": [
{ "run_id": "wfrun_1" },
{ "run_id": "wfrun_2", "step_id": "for_each-0" }
],
"n_consensus": 5
}'
{
"id": "exp_abc",
"workflow_id": "wf_abc123",
"block_id": "extract-invoice",
"block_kind": "extract",
"n_consensus": 5,
"document_count": 2,
"name": "Q1 invoices",
"last_run_id": null,
"status": "draft",
"score": null,
"is_stale": false,
"schema_drift": "unknown",
"schema_drift_detail": null,
"created_at": "2026-05-01T14:30:00Z",
"updated_at": "2026-05-01T14:30:00Z"
}
{
"detail": "Provide at least one document or document capture."
}
{
"detail": "Block not found: extract-invoice"
}
Create a consensus experiment on a supported block (
extract, classifier,
split, or for_each configured with map_method="split_by_key"). The
experiment freezes a name, a fixed document set, and a consensus count — but
does NOT run metrics. Trigger the first run with
Run Experiment.
The create route is flat: send workflow_id in the request body.
Provide documents through one or both of:
document_captures— references to past workflow runs. The handle inputs the block actually received are materialized server-side.documents— explicit handle inputs you assemble yourself, optionally carrying source metadata.
n_consensus must be 3, 5, or 7. See Experiments
for the full conceptual model.
from retab import Retab
client = Retab()
experiment = client.workflows.experiments.create(
workflow_id="wf_abc123",
block_id="extract-invoice",
name="Q1 invoices",
document_captures=[
{"run_id": "wfrun_1"},
{"run_id": "wfrun_2", "step_id": "for_each-0"},
],
n_consensus=5,
)
print(experiment.id)
import { Retab } from "@retab/node";
const client = new Retab({ apiKey: process.env.RETAB_API_KEY });
const experiment = await client.workflows.experiments.create("wf_abc123", "extract-invoice", [
{ runId: "wfrun_1" },
{ runId: "wfrun_2", stepId: "for_each-0" },
], undefined, 5, "Q1 invoices");
console.log(experiment.id);
package main
import (
"context"
"fmt"
"log"
retab "github.com/retab-dev/retab/clients/go"
)
func ptr[T any](v T) *T { return &v }
func main() {
ctx := context.Background()
client, err := retab.NewClient("")
if err != nil {
log.Fatal(err)
}
experiment, err := client.Workflows.Experiments.Create(ctx, &retab.WorkflowExperimentsCreateParams{
WorkflowID: "wf_abc123",
BlockID: ptr("extract-invoice"),
Name: ptr("Q1 invoices"),
DocumentCaptures: []*retab.ExperimentDocumentCaptureRequest{
{RunID: "wfrun_1"},
{RunID: "wfrun_2", StepID: ptr("for_each-0")},
},
NConsensus: ptr(retab.CreateExperimentRequestNConsensus5),
})
if err != nil {
log.Fatal(err)
}
fmt.Println(experiment.ID)
}
require 'retab'
client = Retab::Client.new(api_key: ENV['RETAB_API_KEY'])
experiment = client.workflows.experiments.create(
workflow_id: 'wf_abc123',
block_id: 'extract-invoice',
name: 'Q1 invoices',
document_captures: [
{ run_id: 'wfrun_1' },
{ run_id: 'wfrun_2', step_id: 'for_each-0' },
],
n_consensus: 5,
)
puts experiment.id
use retab::enums::CreateExperimentRequestNConsensus;
use retab::models::{CreateExperimentRequest, ExperimentDocumentCaptureRequest};
use retab::resources::workflow_experiments::CreateParams;
use retab::Retab;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = Retab::new(std::env::var("RETAB_API_KEY")?);
let mut body = CreateExperimentRequest::new("wf_abc123");
body.block_id = Some("extract-invoice".into());
body.name = Some("Q1 invoices".into());
body.document_captures = Some(vec![
ExperimentDocumentCaptureRequest::new("wfrun_1"),
ExperimentDocumentCaptureRequest {
run_id: "wfrun_2".into(),
step_id: Some("for_each-0".into()),
},
]);
body.n_consensus = Some(CreateExperimentRequestNConsensus::V5);
let experiment = client
.workflows().experiments()
.create(CreateParams::new(body))
.await?;
println!("{}", experiment.id);
Ok(())
}
<?php
require 'vendor/autoload.php';
use Retab\Client;
$client = new Client(apiKey: getenv('RETAB_API_KEY'));
$result = $client->workflows()->experiments()->create(
workflowId: 'wf_abc123',
);
print_r($result);
using Retab;
using RetabClient = Retab.Retab;
var apiKey = Environment.GetEnvironmentVariable("RETAB_API_KEY")!;
var client = new RetabClient(apiKey);
var result = await client.Workflows.Experiments.CreateAsync(new WorkflowExperimentsCreateOptions());
Console.WriteLine(result);
import com.retab.RetabClient;
public final class Example {
public static void main(String[] args) throws Exception {
RetabClient client = new RetabClient(System.getenv("RETAB_API_KEY"));
var result = client.workflows().experiments().create("wf_abc123", "block_abc123", null, null, null, "Invoice Processing", null);
System.out.println(result);
}
}
curl -X 'POST' \
'https://api.retab.com/v1/workflows/experiments' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <your-api-key>' \
-d '{
"workflow_id": "wf_abc123",
"block_id": "extract-invoice",
"name": "Q1 invoices",
"document_captures": [
{ "run_id": "wfrun_1" },
{ "run_id": "wfrun_2", "step_id": "for_each-0" }
],
"n_consensus": 5
}'
{
"id": "exp_abc",
"workflow_id": "wf_abc123",
"block_id": "extract-invoice",
"block_kind": "extract",
"n_consensus": 5,
"document_count": 2,
"name": "Q1 invoices",
"last_run_id": null,
"status": "draft",
"score": null,
"is_stale": false,
"schema_drift": "unknown",
"schema_drift_detail": null,
"created_at": "2026-05-01T14:30:00Z",
"updated_at": "2026-05-01T14:30:00Z"
}
{
"detail": "Provide at least one document or document capture."
}
{
"detail": "Block not found: extract-invoice"
}
Authorizations
Bearer authentication header of the form Bearer <token>, where <token> is your auth token.
Body
application/json
Create an experiment, in one of two modes.
- Create from scratch — provide
block_id,name, optionaldocument_captures/documents/n_consensus. Leavesource_experiment_idunset. - Duplicate an existing experiment — provide only
source_experiment_id. The source's block, name (with a(Copy)suffix),n_consensus, and documents are copied. All other fields must be omitted.
Combining source_experiment_id with any other field is rejected.
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Available options:
3, 5, 7 Response
Successful Response
An experiment that evaluates a workflow block against a set of documents, with its latest run status and score.
Available options:
3, 5, 7 Available options:
extract, classifier, split, for_each When the experiment was created
When the experiment was last updated
Available options:
draft, processing, completed, failed, cancelled Show child attributes
Show child attributes
Available options:
fresh, stale, unknown Available options:
run, noop, conflict, unknown Available options:
none, partial, drifted, unknown Show child attributes
Show child attributes