from retab import Retab
client = Retab()
# Rename only.
test = client.workflows.tests.update(
test_id="wfnodetest_hsLEQiM61ez9Piv147MWk",
name="Q1 invoice — vendor name check",
)
# Replace the assertion.
test = client.workflows.tests.update(
test_id="wfnodetest_hsLEQiM61ez9Piv147MWk",
assertion={
"target": {"output_handle_id": "output-json-0", "path": "vendor.name"},
"condition": {"kind": "matches_regex", "expected": r"^Acme.*"},
},
)
# Re-capture inputs from a different run.
test = client.workflows.tests.update(
test_id="wfnodetest_hsLEQiM61ez9Piv147MWk",
source={
"type": "run_step",
"run_id": "wfrun_new789",
"step_id": "block_extract_invoice",
},
)
import { Retab } from "@retab/node";
const client = new Retab({ apiKey: process.env.RETAB_API_KEY });
const renamed = await client.workflows.tests.update("wfnodetest_hsLEQiM61ez9Piv147MWk", "Q1 invoice — vendor name check");
const reAsserted = await client.workflows.tests.update("wfnodetest_hsLEQiM61ez9Piv147MWk", undefined, {
target: { outputHandleId: "output-json-0", path: "vendor.name" },
condition: { kind: "matches_regex", pattern: "^Acme.*" },
});
package main
import (
"context"
"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)
}
testID := "wfnodetest_hsLEQiM61ez9Piv147MWk"
// Rename only.
if _, err := client.Workflows.Tests.Update(ctx, testID, &retab.WorkflowTestsUpdateParams{
Name: ptr("Q1 invoice — vendor name check"),
}); err != nil {
log.Fatal(err)
}
// Replace the assertion.
if _, err := client.Workflows.Tests.Update(ctx, testID, &retab.WorkflowTestsUpdateParams{
Assertion: &retab.AssertionSpec{
Target: retab.OutputTarget{OutputHandleID: "output-json-0", Path: ptr("vendor.name")},
Condition: retab.ConditionFromExistCondition(retab.ExistCondition{Kind: ptr("exists")}),
},
}); err != nil {
log.Fatal(err)
}
// Re-capture inputs from a different run.
if _, err := client.Workflows.Tests.Update(ctx, testID, &retab.WorkflowTestsUpdateParams{
Source: ptr(retab.WorkflowTestSourceFromManualWorkflowTestSource(retab.ManualWorkflowTestSource{
Type: ptr("manual"),
})),
}); err != nil {
log.Fatal(err)
}
}
require 'retab'
client = Retab::Client.new(api_key: ENV['RETAB_API_KEY'])
# Rename only.
test = client.workflow_tests.update(
test_id: 'wfnodetest_hsLEQiM61ez9Piv147MWk',
name: 'Q1 invoice — vendor name check',
)
# Replace the assertion.
test = client.workflow_tests.update(
test_id: 'wfnodetest_hsLEQiM61ez9Piv147MWk',
assertion: {
target: { output_handle_id: 'output-json-0', path: 'vendor.name' },
condition: { kind: 'matches_regex', expected: '^Acme.*' },
},
)
# Re-capture inputs from a different run.
test = client.workflow_tests.update(
test_id: 'wfnodetest_hsLEQiM61ez9Piv147MWk',
source: {
type: 'run_step',
run_id: 'wfrun_new789',
step_id: 'block_extract_invoice',
},
)
use retab::models::{RunStepWorkflowTestSource, UpdateWorkflowTestRequest};
use retab::resources::workflow_tests::UpdateParams;
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 test_id = "wfnodetest_hsLEQiM61ez9Piv147MWk";
// Rename only.
let renamed_body = UpdateWorkflowTestRequest {
name: Some("Q1 invoice — vendor name check".into()),
..Default::default()
};
let _renamed = client
.workflows().tests()
.update(test_id, UpdateParams::new(renamed_body))
.await?;
// Re-capture inputs from a different run.
let mut source = RunStepWorkflowTestSource::new("wfrun_new789");
source.step_id = Some("block_extract_invoice".into());
let resource_body = UpdateWorkflowTestRequest {
source: Some(source.into()),
..Default::default()
};
let _rebound = client
.workflows().tests()
.update(test_id, UpdateParams::new(resource_body))
.await?;
Ok(())
}
<?php
require 'vendor/autoload.php';
use Retab\Client;
$client = new Client(apiKey: getenv('RETAB_API_KEY'));
$result = $client->workflowTests()->update(
testId: 'test_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.Tests.UpdateAsync("test_abc123", new WorkflowTestsUpdateOptions());
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().tests().update("test_abc123", "Invoice Processing", null, null);
System.out.println(result);
}
}
# Rename only
curl -X 'PATCH' \
'https://api.retab.com/v1/workflows/tests/wfnodetest_hsLEQiM61ez9Piv147MWk' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <your-api-key>' \
-d '{ "name": "Q1 invoice — vendor name check" }'
# Replace the assertion
curl -X 'PATCH' \
'https://api.retab.com/v1/workflows/tests/wfnodetest_hsLEQiM61ez9Piv147MWk' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <your-api-key>' \
-d '{
"assertion": {
"target": { "output_handle_id": "output-json-0", "path": "vendor.name" },
"condition": { "kind": "matches_regex", "expected": "^Acme.*" }
}
}'
{
"id": "wfnodetest_hsLEQiM61ez9Piv147MWk",
"workflow_id": "wf_abc123xyz",
"target": { "type": "block", "block_id": "block_extract_invoice" },
"source": { "type": "manual", "handle_inputs": { "...": "..." } },
"name": "Q1 invoice — vendor name check",
"assertion": { "...": "the new assertion" },
"schema_drift": "none",
"validation_status": "valid",
"latest_run_summary": null,
"created_at": "2026-04-08T14:22:26Z",
"updated_at": "2026-05-01T14:35:00Z"
}
{
"detail": "assertion cannot be null"
}
{
"detail": "Workflow test not found: wfnodetest_hsLEQiM61ez9Piv147MWk"
}
Update Workflow Test
Update a workflow test.
Identified by test_id. Send any of name, assertion, or source;
omitted fields are left unchanged. Returns the updated test.
from retab import Retab
client = Retab()
# Rename only.
test = client.workflows.tests.update(
test_id="wfnodetest_hsLEQiM61ez9Piv147MWk",
name="Q1 invoice — vendor name check",
)
# Replace the assertion.
test = client.workflows.tests.update(
test_id="wfnodetest_hsLEQiM61ez9Piv147MWk",
assertion={
"target": {"output_handle_id": "output-json-0", "path": "vendor.name"},
"condition": {"kind": "matches_regex", "expected": r"^Acme.*"},
},
)
# Re-capture inputs from a different run.
test = client.workflows.tests.update(
test_id="wfnodetest_hsLEQiM61ez9Piv147MWk",
source={
"type": "run_step",
"run_id": "wfrun_new789",
"step_id": "block_extract_invoice",
},
)
import { Retab } from "@retab/node";
const client = new Retab({ apiKey: process.env.RETAB_API_KEY });
const renamed = await client.workflows.tests.update("wfnodetest_hsLEQiM61ez9Piv147MWk", "Q1 invoice — vendor name check");
const reAsserted = await client.workflows.tests.update("wfnodetest_hsLEQiM61ez9Piv147MWk", undefined, {
target: { outputHandleId: "output-json-0", path: "vendor.name" },
condition: { kind: "matches_regex", pattern: "^Acme.*" },
});
package main
import (
"context"
"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)
}
testID := "wfnodetest_hsLEQiM61ez9Piv147MWk"
// Rename only.
if _, err := client.Workflows.Tests.Update(ctx, testID, &retab.WorkflowTestsUpdateParams{
Name: ptr("Q1 invoice — vendor name check"),
}); err != nil {
log.Fatal(err)
}
// Replace the assertion.
if _, err := client.Workflows.Tests.Update(ctx, testID, &retab.WorkflowTestsUpdateParams{
Assertion: &retab.AssertionSpec{
Target: retab.OutputTarget{OutputHandleID: "output-json-0", Path: ptr("vendor.name")},
Condition: retab.ConditionFromExistCondition(retab.ExistCondition{Kind: ptr("exists")}),
},
}); err != nil {
log.Fatal(err)
}
// Re-capture inputs from a different run.
if _, err := client.Workflows.Tests.Update(ctx, testID, &retab.WorkflowTestsUpdateParams{
Source: ptr(retab.WorkflowTestSourceFromManualWorkflowTestSource(retab.ManualWorkflowTestSource{
Type: ptr("manual"),
})),
}); err != nil {
log.Fatal(err)
}
}
require 'retab'
client = Retab::Client.new(api_key: ENV['RETAB_API_KEY'])
# Rename only.
test = client.workflow_tests.update(
test_id: 'wfnodetest_hsLEQiM61ez9Piv147MWk',
name: 'Q1 invoice — vendor name check',
)
# Replace the assertion.
test = client.workflow_tests.update(
test_id: 'wfnodetest_hsLEQiM61ez9Piv147MWk',
assertion: {
target: { output_handle_id: 'output-json-0', path: 'vendor.name' },
condition: { kind: 'matches_regex', expected: '^Acme.*' },
},
)
# Re-capture inputs from a different run.
test = client.workflow_tests.update(
test_id: 'wfnodetest_hsLEQiM61ez9Piv147MWk',
source: {
type: 'run_step',
run_id: 'wfrun_new789',
step_id: 'block_extract_invoice',
},
)
use retab::models::{RunStepWorkflowTestSource, UpdateWorkflowTestRequest};
use retab::resources::workflow_tests::UpdateParams;
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 test_id = "wfnodetest_hsLEQiM61ez9Piv147MWk";
// Rename only.
let renamed_body = UpdateWorkflowTestRequest {
name: Some("Q1 invoice — vendor name check".into()),
..Default::default()
};
let _renamed = client
.workflows().tests()
.update(test_id, UpdateParams::new(renamed_body))
.await?;
// Re-capture inputs from a different run.
let mut source = RunStepWorkflowTestSource::new("wfrun_new789");
source.step_id = Some("block_extract_invoice".into());
let resource_body = UpdateWorkflowTestRequest {
source: Some(source.into()),
..Default::default()
};
let _rebound = client
.workflows().tests()
.update(test_id, UpdateParams::new(resource_body))
.await?;
Ok(())
}
<?php
require 'vendor/autoload.php';
use Retab\Client;
$client = new Client(apiKey: getenv('RETAB_API_KEY'));
$result = $client->workflowTests()->update(
testId: 'test_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.Tests.UpdateAsync("test_abc123", new WorkflowTestsUpdateOptions());
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().tests().update("test_abc123", "Invoice Processing", null, null);
System.out.println(result);
}
}
# Rename only
curl -X 'PATCH' \
'https://api.retab.com/v1/workflows/tests/wfnodetest_hsLEQiM61ez9Piv147MWk' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <your-api-key>' \
-d '{ "name": "Q1 invoice — vendor name check" }'
# Replace the assertion
curl -X 'PATCH' \
'https://api.retab.com/v1/workflows/tests/wfnodetest_hsLEQiM61ez9Piv147MWk' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <your-api-key>' \
-d '{
"assertion": {
"target": { "output_handle_id": "output-json-0", "path": "vendor.name" },
"condition": { "kind": "matches_regex", "expected": "^Acme.*" }
}
}'
{
"id": "wfnodetest_hsLEQiM61ez9Piv147MWk",
"workflow_id": "wf_abc123xyz",
"target": { "type": "block", "block_id": "block_extract_invoice" },
"source": { "type": "manual", "handle_inputs": { "...": "..." } },
"name": "Q1 invoice — vendor name check",
"assertion": { "...": "the new assertion" },
"schema_drift": "none",
"validation_status": "valid",
"latest_run_summary": null,
"created_at": "2026-04-08T14:22:26Z",
"updated_at": "2026-05-01T14:35:00Z"
}
{
"detail": "assertion cannot be null"
}
{
"detail": "Workflow test not found: wfnodetest_hsLEQiM61ez9Piv147MWk"
}
assertion: null is rejected explicitly (use Delete Workflow Test if
you want to remove the test entirely).
Updating source rebinds where the inputs come from:
{ type: "manual", handle_inputs: ... }— switch to hand-written inputs.{ type: "run_step", run_id: ..., step_id: ... }— re-capture inputs from a different workflow run / step.
WorkflowTest.
from retab import Retab
client = Retab()
# Rename only.
test = client.workflows.tests.update(
test_id="wfnodetest_hsLEQiM61ez9Piv147MWk",
name="Q1 invoice — vendor name check",
)
# Replace the assertion.
test = client.workflows.tests.update(
test_id="wfnodetest_hsLEQiM61ez9Piv147MWk",
assertion={
"target": {"output_handle_id": "output-json-0", "path": "vendor.name"},
"condition": {"kind": "matches_regex", "expected": r"^Acme.*"},
},
)
# Re-capture inputs from a different run.
test = client.workflows.tests.update(
test_id="wfnodetest_hsLEQiM61ez9Piv147MWk",
source={
"type": "run_step",
"run_id": "wfrun_new789",
"step_id": "block_extract_invoice",
},
)
import { Retab } from "@retab/node";
const client = new Retab({ apiKey: process.env.RETAB_API_KEY });
const renamed = await client.workflows.tests.update("wfnodetest_hsLEQiM61ez9Piv147MWk", "Q1 invoice — vendor name check");
const reAsserted = await client.workflows.tests.update("wfnodetest_hsLEQiM61ez9Piv147MWk", undefined, {
target: { outputHandleId: "output-json-0", path: "vendor.name" },
condition: { kind: "matches_regex", pattern: "^Acme.*" },
});
package main
import (
"context"
"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)
}
testID := "wfnodetest_hsLEQiM61ez9Piv147MWk"
// Rename only.
if _, err := client.Workflows.Tests.Update(ctx, testID, &retab.WorkflowTestsUpdateParams{
Name: ptr("Q1 invoice — vendor name check"),
}); err != nil {
log.Fatal(err)
}
// Replace the assertion.
if _, err := client.Workflows.Tests.Update(ctx, testID, &retab.WorkflowTestsUpdateParams{
Assertion: &retab.AssertionSpec{
Target: retab.OutputTarget{OutputHandleID: "output-json-0", Path: ptr("vendor.name")},
Condition: retab.ConditionFromExistCondition(retab.ExistCondition{Kind: ptr("exists")}),
},
}); err != nil {
log.Fatal(err)
}
// Re-capture inputs from a different run.
if _, err := client.Workflows.Tests.Update(ctx, testID, &retab.WorkflowTestsUpdateParams{
Source: ptr(retab.WorkflowTestSourceFromManualWorkflowTestSource(retab.ManualWorkflowTestSource{
Type: ptr("manual"),
})),
}); err != nil {
log.Fatal(err)
}
}
require 'retab'
client = Retab::Client.new(api_key: ENV['RETAB_API_KEY'])
# Rename only.
test = client.workflow_tests.update(
test_id: 'wfnodetest_hsLEQiM61ez9Piv147MWk',
name: 'Q1 invoice — vendor name check',
)
# Replace the assertion.
test = client.workflow_tests.update(
test_id: 'wfnodetest_hsLEQiM61ez9Piv147MWk',
assertion: {
target: { output_handle_id: 'output-json-0', path: 'vendor.name' },
condition: { kind: 'matches_regex', expected: '^Acme.*' },
},
)
# Re-capture inputs from a different run.
test = client.workflow_tests.update(
test_id: 'wfnodetest_hsLEQiM61ez9Piv147MWk',
source: {
type: 'run_step',
run_id: 'wfrun_new789',
step_id: 'block_extract_invoice',
},
)
use retab::models::{RunStepWorkflowTestSource, UpdateWorkflowTestRequest};
use retab::resources::workflow_tests::UpdateParams;
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 test_id = "wfnodetest_hsLEQiM61ez9Piv147MWk";
// Rename only.
let renamed_body = UpdateWorkflowTestRequest {
name: Some("Q1 invoice — vendor name check".into()),
..Default::default()
};
let _renamed = client
.workflows().tests()
.update(test_id, UpdateParams::new(renamed_body))
.await?;
// Re-capture inputs from a different run.
let mut source = RunStepWorkflowTestSource::new("wfrun_new789");
source.step_id = Some("block_extract_invoice".into());
let resource_body = UpdateWorkflowTestRequest {
source: Some(source.into()),
..Default::default()
};
let _rebound = client
.workflows().tests()
.update(test_id, UpdateParams::new(resource_body))
.await?;
Ok(())
}
<?php
require 'vendor/autoload.php';
use Retab\Client;
$client = new Client(apiKey: getenv('RETAB_API_KEY'));
$result = $client->workflowTests()->update(
testId: 'test_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.Tests.UpdateAsync("test_abc123", new WorkflowTestsUpdateOptions());
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().tests().update("test_abc123", "Invoice Processing", null, null);
System.out.println(result);
}
}
# Rename only
curl -X 'PATCH' \
'https://api.retab.com/v1/workflows/tests/wfnodetest_hsLEQiM61ez9Piv147MWk' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <your-api-key>' \
-d '{ "name": "Q1 invoice — vendor name check" }'
# Replace the assertion
curl -X 'PATCH' \
'https://api.retab.com/v1/workflows/tests/wfnodetest_hsLEQiM61ez9Piv147MWk' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <your-api-key>' \
-d '{
"assertion": {
"target": { "output_handle_id": "output-json-0", "path": "vendor.name" },
"condition": { "kind": "matches_regex", "expected": "^Acme.*" }
}
}'
{
"id": "wfnodetest_hsLEQiM61ez9Piv147MWk",
"workflow_id": "wf_abc123xyz",
"target": { "type": "block", "block_id": "block_extract_invoice" },
"source": { "type": "manual", "handle_inputs": { "...": "..." } },
"name": "Q1 invoice — vendor name check",
"assertion": { "...": "the new assertion" },
"schema_drift": "none",
"validation_status": "valid",
"latest_run_summary": null,
"created_at": "2026-04-08T14:22:26Z",
"updated_at": "2026-05-01T14:35:00Z"
}
{
"detail": "assertion cannot be null"
}
{
"detail": "Workflow test not found: wfnodetest_hsLEQiM61ez9Piv147MWk"
}
Authorizations
Bearer authentication header of the form Bearer <token>, where <token> is your auth token.
Path Parameters
Body
Body for updating a workflow test. Only the supplied fields (name, assertion, source) are changed.
Block-test assertion against one declared output handle.
target is the only supported shape: an output handle id and an
optional relative path inside that handle's payload.
Show child attributes
Show child attributes
- ManualWorkflowTestSource
- RunStepWorkflowTestSource
Show child attributes
Show child attributes
Response
Successful Response
A saved workflow test: a target block, an input source, and the assertion evaluated against its output.
Public workflow-test target.
The storage layer remains block-scoped today, but the API shape names the tested entity explicitly so workflow-level targets can be added later.
Show child attributes
Show child attributes
- ManualWorkflowTestSource
- RunStepWorkflowTestSource
Show child attributes
Show child attributes
Block-test assertion against one declared output handle.
target is the only supported shape: an output handle id and an
optional relative path inside that handle's payload.
Show child attributes
Show child attributes
Single-rule schema dependency for Level 2 drift detection.
Show child attributes
Show child attributes
valid, drifted, broken none, partial, drifted, unknown Show child attributes
Show child attributes
Show child attributes
Show child attributes
Summary of the most recent block-test run.
Execution status and verdict outcome are exposed as separate fields.
The summary is written on terminal-state transitions, so in practice
status is one of completed | error | cancelled and outcome is
populated when status == "completed".
Show child attributes
Show child attributes
Summary of the most recent block-test run.
Execution status and verdict outcome are exposed as separate fields.
The summary is written on terminal-state transitions, so in practice
status is one of completed | error | cancelled and outcome is
populated when status == "completed".
Show child attributes
Show child attributes
Summary of the most recent block-test run.
Execution status and verdict outcome are exposed as separate fields.
The summary is written on terminal-state transitions, so in practice
status is one of completed | error | cancelled and outcome is
populated when status == "completed".
Show child attributes
Show child attributes
When the workflow test was created
When the workflow test was last updated