from retab import Retab
client = Retab()
# A typical extract block with a JSON schema config
block = client.workflows.blocks.create(
workflow_id="wf_abc123xyz",
id="extract-1",
type="extract",
label="Extract Invoice Fields",
position_x=320,
position_y=0,
config={
"model": "gpt-5",
"json_schema": {
"type": "object",
"properties": {
"invoice_number": {"type": "string"},
"total": {"type": "number"},
},
},
},
)
print(block.id)
import { Retab } from "@retab/node";
const client = new Retab({ apiKey: process.env.RETAB_API_KEY });
const block = await client.workflows.blocks.create("wf_abc123xyz", "extract", "extract-1", "Extract Invoice Fields", 320, 0, undefined, undefined, {
model: "retab-small",
json_schema: {
type: "object",
properties: {
invoice_number: { type: "string" },
total: { type: "number" },
},
},
});
console.log(block.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)
}
block, err := client.Workflows.Blocks.Create(ctx, &retab.WorkflowBlocksCreateParams{
WorkflowID: "wf_abc123xyz",
ID: ptr("extract-1"),
Type: "extract",
Label: ptr("Extract Invoice Fields"),
PositionX: ptr(320.0),
PositionY: ptr(0.0),
Config: &map[string]any{
"model": "gpt-5",
"json_schema": map[string]any{
"type": "object",
"properties": map[string]any{
"invoice_number": map[string]any{"type": "string"},
"total": map[string]any{"type": "number"},
},
},
},
})
if err != nil {
log.Fatal(err)
}
fmt.Println(block.ID)
}
require 'retab'
client = Retab::Client.new(api_key: ENV['RETAB_API_KEY'])
block = client.workflows.blocks.create(
workflow_id: 'wf_abc123xyz',
id: 'extract-1',
type: 'extract',
label: 'Extract Invoice Fields',
position_x: 320,
position_y: 0,
config: {
model: 'gpt-5',
json_schema: {
type: 'object',
properties: {
invoice_number: { type: 'string' },
total: { type: 'number' },
},
},
},
)
puts block.id
use retab::enums::WorkflowBlockCreateRequestType;
use retab::models::WorkflowBlockCreateRequest;
use retab::resources::workflow_blocks::CreateParams;
use retab::Retab;
use serde_json::json;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = Retab::new(std::env::var("RETAB_API_KEY")?);
let config = serde_json::from_value(json!({
"model": "gpt-5",
"json_schema": {
"type": "object",
"properties": {
"invoice_number": {"type": "string"},
"total": {"type": "number"},
},
},
}))?;
let block = client
.workflows().blocks()
.create(CreateParams::new(WorkflowBlockCreateRequest {
workflow_id: "wf_abc123xyz".into(),
id: Some("extract-1".into()),
type_: WorkflowBlockCreateRequestType::Extract,
label: Some("Extract Invoice Fields".into()),
position_x: Some(320.0),
position_y: Some(0.0),
width: None,
height: None,
config: Some(config),
parent_id: None,
}))
.await?;
println!("{}", block.id);
Ok(())
}
<?php
require 'vendor/autoload.php';
use Retab\Client;
use Retab\Resource\WorkflowBlockCreateRequestType;
$client = new Client(apiKey: getenv('RETAB_API_KEY'));
$result = $client->workflows()->blocks()->create(
workflowId: 'wf_abc123',
type: WorkflowBlockCreateRequestType::Extract,
id: 'extract-1',
label: 'Extract Invoice Fields',
);
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.Blocks.CreateAsync(new WorkflowBlocksCreateOptions());
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().blocks().create("wf_abc123", null, null, null, null, null, null, null, null, null);
System.out.println(result);
}
}
curl -X 'POST' \
'https://api.retab.com/v1/workflows/blocks' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <your-api-key>' \
-d '{
"workflow_id": "wf_abc123xyz",
"id": "extract-1",
"type": "extract",
"label": "Extract Invoice Fields",
"position_x": 320,
"position_y": 0,
"config": {
"model": "gpt-5",
"json_schema": {
"type": "object",
"properties": {
"invoice_number": {"type": "string"},
"total": {"type": "number"}
}
}
}
}'
{
"id": "extract-1",
"workflow_id": "wf_abc123xyz",
"type": "extract",
"label": "Extract Invoice Fields",
"position_x": 320,
"position_y": 0,
"width": null,
"height": null,
"config": {
"model": "gpt-5",
"json_schema": {
"type": "object",
"properties": {
"invoice_number": { "type": "string" },
"total": { "type": "number" }
}
}
},
"parent_id": null,
"updated_at": "2026-05-01T14:30:00Z"
}
{
"detail": "Input blocks (start_document, start_json) cannot be placed inside containers"
}
{
"detail": "Workflow not found"
}
{
"detail": "Block ID 'extract-1' already exists"
}
Create Block
Create a new block in a workflow.
from retab import Retab
client = Retab()
# A typical extract block with a JSON schema config
block = client.workflows.blocks.create(
workflow_id="wf_abc123xyz",
id="extract-1",
type="extract",
label="Extract Invoice Fields",
position_x=320,
position_y=0,
config={
"model": "gpt-5",
"json_schema": {
"type": "object",
"properties": {
"invoice_number": {"type": "string"},
"total": {"type": "number"},
},
},
},
)
print(block.id)
import { Retab } from "@retab/node";
const client = new Retab({ apiKey: process.env.RETAB_API_KEY });
const block = await client.workflows.blocks.create("wf_abc123xyz", "extract", "extract-1", "Extract Invoice Fields", 320, 0, undefined, undefined, {
model: "retab-small",
json_schema: {
type: "object",
properties: {
invoice_number: { type: "string" },
total: { type: "number" },
},
},
});
console.log(block.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)
}
block, err := client.Workflows.Blocks.Create(ctx, &retab.WorkflowBlocksCreateParams{
WorkflowID: "wf_abc123xyz",
ID: ptr("extract-1"),
Type: "extract",
Label: ptr("Extract Invoice Fields"),
PositionX: ptr(320.0),
PositionY: ptr(0.0),
Config: &map[string]any{
"model": "gpt-5",
"json_schema": map[string]any{
"type": "object",
"properties": map[string]any{
"invoice_number": map[string]any{"type": "string"},
"total": map[string]any{"type": "number"},
},
},
},
})
if err != nil {
log.Fatal(err)
}
fmt.Println(block.ID)
}
require 'retab'
client = Retab::Client.new(api_key: ENV['RETAB_API_KEY'])
block = client.workflows.blocks.create(
workflow_id: 'wf_abc123xyz',
id: 'extract-1',
type: 'extract',
label: 'Extract Invoice Fields',
position_x: 320,
position_y: 0,
config: {
model: 'gpt-5',
json_schema: {
type: 'object',
properties: {
invoice_number: { type: 'string' },
total: { type: 'number' },
},
},
},
)
puts block.id
use retab::enums::WorkflowBlockCreateRequestType;
use retab::models::WorkflowBlockCreateRequest;
use retab::resources::workflow_blocks::CreateParams;
use retab::Retab;
use serde_json::json;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = Retab::new(std::env::var("RETAB_API_KEY")?);
let config = serde_json::from_value(json!({
"model": "gpt-5",
"json_schema": {
"type": "object",
"properties": {
"invoice_number": {"type": "string"},
"total": {"type": "number"},
},
},
}))?;
let block = client
.workflows().blocks()
.create(CreateParams::new(WorkflowBlockCreateRequest {
workflow_id: "wf_abc123xyz".into(),
id: Some("extract-1".into()),
type_: WorkflowBlockCreateRequestType::Extract,
label: Some("Extract Invoice Fields".into()),
position_x: Some(320.0),
position_y: Some(0.0),
width: None,
height: None,
config: Some(config),
parent_id: None,
}))
.await?;
println!("{}", block.id);
Ok(())
}
<?php
require 'vendor/autoload.php';
use Retab\Client;
use Retab\Resource\WorkflowBlockCreateRequestType;
$client = new Client(apiKey: getenv('RETAB_API_KEY'));
$result = $client->workflows()->blocks()->create(
workflowId: 'wf_abc123',
type: WorkflowBlockCreateRequestType::Extract,
id: 'extract-1',
label: 'Extract Invoice Fields',
);
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.Blocks.CreateAsync(new WorkflowBlocksCreateOptions());
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().blocks().create("wf_abc123", null, null, null, null, null, null, null, null, null);
System.out.println(result);
}
}
curl -X 'POST' \
'https://api.retab.com/v1/workflows/blocks' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <your-api-key>' \
-d '{
"workflow_id": "wf_abc123xyz",
"id": "extract-1",
"type": "extract",
"label": "Extract Invoice Fields",
"position_x": 320,
"position_y": 0,
"config": {
"model": "gpt-5",
"json_schema": {
"type": "object",
"properties": {
"invoice_number": {"type": "string"},
"total": {"type": "number"}
}
}
}
}'
{
"id": "extract-1",
"workflow_id": "wf_abc123xyz",
"type": "extract",
"label": "Extract Invoice Fields",
"position_x": 320,
"position_y": 0,
"width": null,
"height": null,
"config": {
"model": "gpt-5",
"json_schema": {
"type": "object",
"properties": {
"invoice_number": { "type": "string" },
"total": { "type": "number" }
}
}
},
"parent_id": null,
"updated_at": "2026-05-01T14:30:00Z"
}
{
"detail": "Input blocks (start_document, start_json) cannot be placed inside containers"
}
{
"detail": "Workflow not found"
}
{
"detail": "Block ID 'extract-1' already exists"
}
workflow_id in the request body.
You provide the block ID — it must be unique within the workflow. Pick something descriptive (e.g. extract-invoice, classifier-language) so edges and assertions stay readable.
The config shape depends on type. See Workflow Blocks for the per-type config reference.
A few invariants the API enforces:
- Input blocks (
start_document,start_json) cannot be placed inside containers —parent_idmust benullfor them. parent_idis reserved for placing blocks inside container blocks (while_loop,for_each).
from retab import Retab
client = Retab()
# A typical extract block with a JSON schema config
block = client.workflows.blocks.create(
workflow_id="wf_abc123xyz",
id="extract-1",
type="extract",
label="Extract Invoice Fields",
position_x=320,
position_y=0,
config={
"model": "gpt-5",
"json_schema": {
"type": "object",
"properties": {
"invoice_number": {"type": "string"},
"total": {"type": "number"},
},
},
},
)
print(block.id)
import { Retab } from "@retab/node";
const client = new Retab({ apiKey: process.env.RETAB_API_KEY });
const block = await client.workflows.blocks.create("wf_abc123xyz", "extract", "extract-1", "Extract Invoice Fields", 320, 0, undefined, undefined, {
model: "retab-small",
json_schema: {
type: "object",
properties: {
invoice_number: { type: "string" },
total: { type: "number" },
},
},
});
console.log(block.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)
}
block, err := client.Workflows.Blocks.Create(ctx, &retab.WorkflowBlocksCreateParams{
WorkflowID: "wf_abc123xyz",
ID: ptr("extract-1"),
Type: "extract",
Label: ptr("Extract Invoice Fields"),
PositionX: ptr(320.0),
PositionY: ptr(0.0),
Config: &map[string]any{
"model": "gpt-5",
"json_schema": map[string]any{
"type": "object",
"properties": map[string]any{
"invoice_number": map[string]any{"type": "string"},
"total": map[string]any{"type": "number"},
},
},
},
})
if err != nil {
log.Fatal(err)
}
fmt.Println(block.ID)
}
require 'retab'
client = Retab::Client.new(api_key: ENV['RETAB_API_KEY'])
block = client.workflows.blocks.create(
workflow_id: 'wf_abc123xyz',
id: 'extract-1',
type: 'extract',
label: 'Extract Invoice Fields',
position_x: 320,
position_y: 0,
config: {
model: 'gpt-5',
json_schema: {
type: 'object',
properties: {
invoice_number: { type: 'string' },
total: { type: 'number' },
},
},
},
)
puts block.id
use retab::enums::WorkflowBlockCreateRequestType;
use retab::models::WorkflowBlockCreateRequest;
use retab::resources::workflow_blocks::CreateParams;
use retab::Retab;
use serde_json::json;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = Retab::new(std::env::var("RETAB_API_KEY")?);
let config = serde_json::from_value(json!({
"model": "gpt-5",
"json_schema": {
"type": "object",
"properties": {
"invoice_number": {"type": "string"},
"total": {"type": "number"},
},
},
}))?;
let block = client
.workflows().blocks()
.create(CreateParams::new(WorkflowBlockCreateRequest {
workflow_id: "wf_abc123xyz".into(),
id: Some("extract-1".into()),
type_: WorkflowBlockCreateRequestType::Extract,
label: Some("Extract Invoice Fields".into()),
position_x: Some(320.0),
position_y: Some(0.0),
width: None,
height: None,
config: Some(config),
parent_id: None,
}))
.await?;
println!("{}", block.id);
Ok(())
}
<?php
require 'vendor/autoload.php';
use Retab\Client;
use Retab\Resource\WorkflowBlockCreateRequestType;
$client = new Client(apiKey: getenv('RETAB_API_KEY'));
$result = $client->workflows()->blocks()->create(
workflowId: 'wf_abc123',
type: WorkflowBlockCreateRequestType::Extract,
id: 'extract-1',
label: 'Extract Invoice Fields',
);
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.Blocks.CreateAsync(new WorkflowBlocksCreateOptions());
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().blocks().create("wf_abc123", null, null, null, null, null, null, null, null, null);
System.out.println(result);
}
}
curl -X 'POST' \
'https://api.retab.com/v1/workflows/blocks' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <your-api-key>' \
-d '{
"workflow_id": "wf_abc123xyz",
"id": "extract-1",
"type": "extract",
"label": "Extract Invoice Fields",
"position_x": 320,
"position_y": 0,
"config": {
"model": "gpt-5",
"json_schema": {
"type": "object",
"properties": {
"invoice_number": {"type": "string"},
"total": {"type": "number"}
}
}
}
}'
{
"id": "extract-1",
"workflow_id": "wf_abc123xyz",
"type": "extract",
"label": "Extract Invoice Fields",
"position_x": 320,
"position_y": 0,
"width": null,
"height": null,
"config": {
"model": "gpt-5",
"json_schema": {
"type": "object",
"properties": {
"invoice_number": { "type": "string" },
"total": { "type": "number" }
}
}
},
"parent_id": null,
"updated_at": "2026-05-01T14:30:00Z"
}
{
"detail": "Input blocks (start_document, start_json) cannot be placed inside containers"
}
{
"detail": "Workflow not found"
}
{
"detail": "Block ID 'extract-1' already exists"
}
Authorizations
Bearer authentication header of the form Bearer <token>, where <token> is your auth token.
Body
Create a new block in a workflow.
Workflow to create the block in.
Block type
start_document, start_json, note, parse, edit, extract, split, classifier, conditional, api_call, function, while_loop, for_each, merge_dicts Block ID. Omit to let the server generate one (recommended). Block IDs must be unique across your organization, not just within a workflow — reusing a custom id like 'block_extract' in more than one workflow fails with 409.
Display label
200X position
Y position
Block width
Block height
Block configuration
ID of parent container block (while_loop, for_each)
Response
Successful Response
Public live workflow block object.
Foreign key to workflow
Block type (extract, parse, classifier, etc.)
start_document, start_json, note, parse, edit, extract, split, classifier, conditional, api_call, function, while_loop, for_each, merge_dicts, while_loop_sentinel_start, while_loop_sentinel_end, for_each_sentinel_start, for_each_sentinel_end Display label for the block
X position on canvas
Y position on canvas
Block width for resizable blocks
Block height for resizable blocks
Block-specific configuration
ID of parent container (while_loop, for_each)
Canonical declarative block path used to reconcile imported specs.
Authored declarative block id before import-time id regeneration.
Schemas resolved for this block from the workflow graph.