Skip to content

Commit acb5e33

Browse files
feat(turbosign): add conditional (IF/THEN) fields to the SDK quickstart (#24)
Adds a "Conditional (IF/THEN) fields" subsection to all six language references (a controlling checkbox with metadata.fieldKey and a dependent field with metadata.conditional { controllingFieldKey, operator, action }), updates the SKILL and README so the skill offers it, and adds an eval. Typed languages use the SDK's real types (Go structs, PHP enums, Java FieldMetadata factories). Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent cc567cd commit acb5e33

9 files changed

Lines changed: 331 additions & 0 deletions

File tree

‎README.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ Skip the product selection prompt:
138138
### TurboSign Integration
139139
- Client configuration with env var loading
140140
- `sendSignature()`, `getStatus()`, `download()` — send, track, retrieve signed PDFs
141+
- Conditional (IF/THEN) fields — a controlling `checkbox` plus dependent fields that show or unlock only when it is ticked (via optional field `metadata`)
141142
- Optional: `void()`, `resend()`, `getAuditTrail()` — cancellation, reminders, tamper-evident audit log
142143
- Route handlers wired into your existing app
143144

‎evals/evals.json‎

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1229,6 +1229,64 @@
12291229
}
12301230
]
12311231
},
1232+
{
1233+
"id": 51,
1234+
"prompt": "Set up TurboSign in my Express app. On the signing document I need a conditional field: the signer ticks a checkbox to opt into relocation assistance, and only then should a second signature field become visible. Add an endpoint that sends this document.",
1235+
"expected_output": "Creates a TurboSign config file and a sendSignature endpoint whose fields array contains a controlling checkbox field with metadata.fieldKey and a dependent field with metadata.conditional (controllingFieldKey matching the checkbox fieldKey, operator is_checked, action show), wires routes into the main app, adds .env with TurboSign vars",
1236+
"files": [
1237+
"package.json",
1238+
"tsconfig.json",
1239+
"src/index.ts",
1240+
"package-lock.json"
1241+
],
1242+
"assertions": [
1243+
{
1244+
"name": "config-file-created",
1245+
"type": "file_exists",
1246+
"description": "A TurboSign config/client file was created"
1247+
},
1248+
{
1249+
"name": "uses-sendSignature",
1250+
"type": "file_contains",
1251+
"description": "Route handler calls TurboSign.sendSignature with a fields array"
1252+
},
1253+
{
1254+
"name": "has-checkbox-field",
1255+
"type": "file_contains",
1256+
"description": "The fields array includes a field with type 'checkbox' acting as the controlling field"
1257+
},
1258+
{
1259+
"name": "checkbox-has-fieldKey",
1260+
"type": "file_contains",
1261+
"description": "The controlling checkbox field carries metadata.fieldKey (a stable id, e.g. metadata: { fieldKey: '...' })"
1262+
},
1263+
{
1264+
"name": "dependent-has-conditional",
1265+
"type": "file_contains",
1266+
"description": "A dependent field carries metadata.conditional with controllingFieldKey, operator, and action keys"
1267+
},
1268+
{
1269+
"name": "controllingFieldKey-matches",
1270+
"type": "file_contains",
1271+
"description": "The dependent field's conditional.controllingFieldKey matches the controlling checkbox's metadata.fieldKey value exactly"
1272+
},
1273+
{
1274+
"name": "uses-valid-operator-and-action",
1275+
"type": "file_contains",
1276+
"description": "conditional.operator is 'is_checked' or 'is_not_checked' and conditional.action is 'show' or 'unlock'"
1277+
},
1278+
{
1279+
"name": "routes-wired",
1280+
"type": "file_contains",
1281+
"description": "Main app file (src/index.ts) was modified to import and register the signature routes"
1282+
},
1283+
{
1284+
"name": "env-has-sign-vars",
1285+
"type": "file_contains",
1286+
"description": ".env contains TURBODOCX_API_KEY and TURBODOCX_SENDER_EMAIL"
1287+
}
1288+
]
1289+
},
12321290
{
12331291
"id": 10,
12341292
"skill_name": "turbodocx-html-to-docx",

‎skills/turbodocx-sdk/SKILL.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ Create working route handlers / endpoint code for the selected product(s). The l
183183

184184
**For TurboSign, generate:**
185185
- `sendSignature()` endpoint — accepts file (or `fileLink` / `deliverableId` / `templateId`), recipients, fields
186+
- If the user wants **conditional (IF/THEN) fields** — a field that shows or unlocks only when the signer ticks a box: add a controlling `checkbox` field carrying `metadata.fieldKey`, and a dependent field carrying `metadata.conditional` (`{ controllingFieldKey, operator: "is_checked" | "is_not_checked", action: "show" | "unlock" }`) whose `controllingFieldKey` matches the checkbox's `fieldKey`. `action: "show"` keeps the dependent field hidden until the condition is met; `action: "unlock"` shows it but read-only until met. `metadata` is optional and both live on the normal `sendSignature()` field array — see the language reference for the exact per-language shape.
186187
- `getStatus()` endpoint — check the document-level status by ID
187188
- `getRecipients()` endpoint — every recipient with their signing status, email history, and who sent the document. Generate this whenever the user wants to know **who has signed / who is still pending**; `getStatus()` alone cannot answer that. Note each recipient carries both `status` (raw: `pending`/`viewed`/`completed`) and `effectiveStatus` (adds `voided`/`expired`) — generated code should branch on `effectiveStatus`, since an unsigned signer on a voided document still reads `pending` in the raw field.
188189
- `download()` endpoint — stream signed PDF (returns `Blob`/`ArrayBuffer` per language)

‎skills/turbodocx-sdk/references/go.md‎

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,58 @@ if err != nil {
7676
fmt.Printf("Document ID: %s\n", result.DocumentID)
7777
```
7878

79+
### Conditional (IF/THEN) fields
80+
81+
Any field can be made to depend on a **controlling checkbox** so it only appears — or only becomes editable — once the signer ticks that box. Give the checkbox a stable `Metadata.FieldKey`, then reference that key from the dependent field's `Metadata.Conditional.ControllingFieldKey`. `Field.Metadata` is an **optional** `*turbodocx.FieldMetadata`; a nil `Metadata` (the default) behaves exactly as before.
82+
83+
```go
84+
result, err := client.TurboSign.SendSignature(ctx, &turbodocx.SendSignatureRequest{
85+
File: pdfFile,
86+
FileName: "contract.pdf",
87+
DocumentName: "Employment Agreement",
88+
Recipients: []turbodocx.Recipient{
89+
{Name: "John Doe", Email: "john@example.com", SigningOrder: 1},
90+
},
91+
Fields: []turbodocx.Field{
92+
// Controlling checkbox — the box the signer ticks. Its FieldKey is the stable id others reference.
93+
{
94+
Type: "checkbox",
95+
RecipientEmail: "john@example.com",
96+
Page: 1,
97+
X: 100,
98+
Y: 400,
99+
Width: 20,
100+
Height: 20,
101+
Metadata: &turbodocx.FieldMetadata{
102+
FieldKey: "relocation_optin",
103+
},
104+
},
105+
// Dependent field — hidden until the box above is checked (Action: "show").
106+
{
107+
Type: "signature",
108+
RecipientEmail: "john@example.com",
109+
Page: 1,
110+
X: 100,
111+
Y: 460,
112+
Width: 200,
113+
Height: 50,
114+
Metadata: &turbodocx.FieldMetadata{
115+
Conditional: &turbodocx.FieldConditional{
116+
ControllingFieldKey: "relocation_optin", // = the checkbox's Metadata.FieldKey
117+
Operator: "is_checked", // "is_checked" | "is_not_checked"
118+
Action: "show", // "show" = hidden until met; "unlock" = visible but read-only until met
119+
},
120+
},
121+
},
122+
},
123+
})
124+
if err != nil {
125+
log.Fatal(err)
126+
}
127+
```
128+
129+
The link is `FieldKey` → `ControllingFieldKey`: the two strings must match exactly (the checkbox carries `Metadata.FieldKey`, the dependent field points at it via `Metadata.Conditional.ControllingFieldKey`). `Operator` chooses which checkbox state satisfies the condition — `"is_checked"` or `"is_not_checked"`. `Action` chooses what happens while the condition is unmet: `"show"` keeps the dependent field **hidden until met**, while `"unlock"` renders it **visible but read-only (locked) until met**.
130+
79131
### GetStatus
80132

81133
```go

‎skills/turbodocx-sdk/references/java.md‎

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,49 @@ SendSignatureResponse result = client.turboSign().sendSignature(
7777
System.out.println("Document ID: " + result.getDocumentId());
7878
```
7979

80+
### Conditional (IF/THEN) fields
81+
82+
Any field can be made to depend on a **controlling checkbox** so it only appears — or only becomes editable — once the signer ticks that box. Give the checkbox a stable `FieldMetadata` with a `fieldKey`, then reference that key from the dependent field's `FieldMetadata` → `FieldConditional` → `controllingFieldKey`. `.metadata(...)` on the builder is **optional**; a field left without it behaves exactly as before.
83+
84+
```java
85+
SendSignatureResponse result = client.turboSign().sendSignature(
86+
new SendSignatureRequest.Builder()
87+
.file(pdfFile)
88+
.fileName("contract.pdf")
89+
.documentName("Employment Agreement")
90+
.recipients(Arrays.asList(
91+
new Recipient("John Doe", "john@example.com", 1)
92+
))
93+
.fields(Arrays.asList(
94+
// Controlling checkbox — the box the signer ticks. Its fieldKey is the stable id others reference.
95+
new Field.Builder()
96+
.type("checkbox")
97+
.recipientEmail("john@example.com")
98+
.page(1)
99+
.x(100).y(400).width(20).height(20)
100+
.metadata(FieldMetadata.forFieldKey("relocation_optin"))
101+
.build(),
102+
// Dependent field — hidden until the box above is checked (action "show").
103+
new Field.Builder()
104+
.type("signature")
105+
.recipientEmail("john@example.com")
106+
.page(1)
107+
.x(100).y(460).width(200).height(50)
108+
.metadata(FieldMetadata.forConditional(
109+
new FieldConditional(
110+
"relocation_optin", // controllingFieldKey = the checkbox's metadata fieldKey
111+
"is_checked", // "is_checked" | "is_not_checked"
112+
"show"))) // "show" = hidden until met; "unlock" = visible but read-only until met
113+
.build()
114+
))
115+
.build()
116+
);
117+
118+
System.out.println("Document ID: " + result.getDocumentId());
119+
```
120+
121+
The link is `fieldKey` → `controllingFieldKey`: the two strings must match exactly (the checkbox carries `FieldMetadata.fieldKey`, the dependent field points at it via `FieldConditional.controllingFieldKey`). `operator` chooses which checkbox state satisfies the condition — `"is_checked"` or `"is_not_checked"`. `action` chooses what happens while the condition is unmet: `"show"` keeps the dependent field **hidden until met**, while `"unlock"` renders it **visible but read-only (locked) until met**.
122+
80123
### getStatus
81124

82125
```java

‎skills/turbodocx-sdk/references/javascript.md‎

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,44 @@ console.log(result.recipients); // ReviewRecipient[] with { id, name, email, m
102102

103103
Fields support either coordinate-based (`page` + `x` / `y` / `width` / `height`) or anchor-based placement via `template: { anchor: '{TagName}', placement: 'replace', size: {...} }`.
104104

105+
### Conditional (IF/THEN) fields
106+
107+
Any field can be made to depend on a **controlling checkbox** so it only appears — or only becomes editable — once the signer ticks that box. Give the checkbox a stable `metadata.fieldKey`, then reference that key from the dependent field's `metadata.conditional.controllingFieldKey`. Both live in an **optional** `metadata` object on the field; fields without it behave exactly as before.
108+
109+
```typescript
110+
const result = await TurboSign.sendSignature({
111+
file: pdfBuffer,
112+
documentName: 'Employment Agreement',
113+
recipients: [
114+
{ name: 'John Doe', email: 'john@example.com', signingOrder: 1 },
115+
],
116+
fields: [
117+
// Controlling checkbox — the box the signer ticks. Its metadata.fieldKey is the stable id others reference.
118+
{
119+
type: 'checkbox',
120+
page: 1, x: 100, y: 400, width: 20, height: 20,
121+
recipientEmail: 'john@example.com',
122+
metadata: { fieldKey: 'relocation_optin' },
123+
},
124+
// Dependent field — hidden until the box above is checked (action: 'show').
125+
{
126+
type: 'signature',
127+
page: 1, x: 100, y: 460, width: 200, height: 50,
128+
recipientEmail: 'john@example.com',
129+
metadata: {
130+
conditional: {
131+
controllingFieldKey: 'relocation_optin', // = the checkbox's metadata.fieldKey
132+
operator: 'is_checked', // 'is_checked' | 'is_not_checked'
133+
action: 'show', // 'show' = hidden until met; 'unlock' = visible but read-only until met
134+
},
135+
},
136+
},
137+
],
138+
});
139+
```
140+
141+
The link is `fieldKey` → `controllingFieldKey`: the two strings must match exactly (the checkbox carries `metadata.fieldKey`, the dependent field points at it via `metadata.conditional.controllingFieldKey`). `operator` chooses which checkbox state satisfies the condition — `is_checked` or `is_not_checked`. `action` chooses what happens while the condition is unmet: `show` keeps the dependent field **hidden until met**, while `unlock` renders it **visible but read-only (locked) until met**.
142+
105143
### TurboSign.getStatus
106144

107145
```typescript

‎skills/turbodocx-sdk/references/php.md‎

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,66 @@ $result = TurboSign::sendSignature(
8383
echo "Document ID: {$result->documentId}\n";
8484
```
8585

86+
### Conditional (IF/THEN) fields
87+
88+
Any field can be made to depend on a **controlling checkbox** so it only appears — or only becomes editable — once the signer ticks that box. Give the checkbox a stable `metadata` with a `fieldKey`, then reference that key from the dependent field's `metadata->conditional->controllingFieldKey`. The `metadata:` argument on `Field` is **optional**; a `Field` without it behaves exactly as before.
89+
90+
```php
91+
use TurboDocx\TurboSign;
92+
use TurboDocx\Types\Recipient;
93+
use TurboDocx\Types\Field;
94+
use TurboDocx\Types\SignatureFieldType;
95+
use TurboDocx\Types\FieldMetadata;
96+
use TurboDocx\Types\FieldConditional;
97+
use TurboDocx\Types\ConditionalOperator;
98+
use TurboDocx\Types\ConditionalAction;
99+
use TurboDocx\Types\Requests\SendSignatureRequest;
100+
101+
$result = TurboSign::sendSignature(
102+
new SendSignatureRequest(
103+
file: file_get_contents('contract.pdf'),
104+
documentName: 'Employment Agreement',
105+
recipients: [
106+
new Recipient('John Doe', 'john@example.com', 1),
107+
],
108+
fields: [
109+
// Controlling checkbox — the box the signer ticks. Its fieldKey is the stable id others reference.
110+
new Field(
111+
type: SignatureFieldType::CHECKBOX,
112+
recipientEmail: 'john@example.com',
113+
page: 1,
114+
x: 100,
115+
y: 400,
116+
width: 20,
117+
height: 20,
118+
metadata: new FieldMetadata(fieldKey: 'relocation_optin'),
119+
),
120+
// Dependent field — hidden until the box above is checked (action: "show").
121+
new Field(
122+
type: SignatureFieldType::SIGNATURE,
123+
recipientEmail: 'john@example.com',
124+
page: 1,
125+
x: 100,
126+
y: 460,
127+
width: 200,
128+
height: 50,
129+
metadata: new FieldMetadata(
130+
conditional: new FieldConditional(
131+
controllingFieldKey: 'relocation_optin', // = the checkbox's metadata fieldKey
132+
operator: ConditionalOperator::IS_CHECKED, // ::IS_CHECKED | ::IS_NOT_CHECKED
133+
action: ConditionalAction::SHOW, // ::SHOW = hidden until met; ::UNLOCK = visible but read-only until met
134+
),
135+
),
136+
),
137+
],
138+
)
139+
);
140+
141+
echo "Document ID: {$result->documentId}\n";
142+
```
143+
144+
The link is `fieldKey` → `controllingFieldKey`: the two strings must match exactly (the checkbox carries `metadata->fieldKey`, the dependent field points at it via `metadata->conditional->controllingFieldKey`). `operator` chooses which checkbox state satisfies the condition — `'is_checked'` or `'is_not_checked'`. `action` chooses what happens while the condition is unmet: `'show'` keeps the dependent field **hidden until met**, while `'unlock'` renders it **visible but read-only (locked) until met**.
145+
86146
### getStatus
87147

88148
```php

‎skills/turbodocx-sdk/references/python.md‎

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,44 @@ result = await TurboSign.send_signature(
7676
print(f"Document ID: {result['documentId']}")
7777
```
7878

79+
### Conditional (IF/THEN) fields
80+
81+
Any field can be made to depend on a **controlling checkbox** so it only appears — or only becomes editable — once the signer ticks that box. Give the checkbox a stable `metadata["fieldKey"]`, then reference that key from the dependent field's `metadata["conditional"]["controllingFieldKey"]`. Both live in an **optional** `metadata` dict on the field; fields without it behave exactly as before. Note the keys inside `metadata` stay camelCase (`fieldKey`, `controllingFieldKey`) — they are forwarded to the API verbatim.
82+
83+
```python
84+
result = await TurboSign.send_signature(
85+
file=pdf_file,
86+
document_name="Employment Agreement",
87+
recipients=[
88+
{"name": "John Doe", "email": "john@example.com", "signingOrder": 1},
89+
],
90+
fields=[
91+
# Controlling checkbox — the box the signer ticks. Its metadata.fieldKey is the stable id others reference.
92+
{
93+
"type": "checkbox",
94+
"page": 1, "x": 100, "y": 400, "width": 20, "height": 20,
95+
"recipientEmail": "john@example.com",
96+
"metadata": {"fieldKey": "relocation_optin"},
97+
},
98+
# Dependent field — hidden until the box above is checked (action: "show").
99+
{
100+
"type": "signature",
101+
"page": 1, "x": 100, "y": 460, "width": 200, "height": 50,
102+
"recipientEmail": "john@example.com",
103+
"metadata": {
104+
"conditional": {
105+
"controllingFieldKey": "relocation_optin", # = the checkbox's metadata.fieldKey
106+
"operator": "is_checked", # "is_checked" | "is_not_checked"
107+
"action": "show", # "show" = hidden until met; "unlock" = visible but read-only until met
108+
},
109+
},
110+
},
111+
],
112+
)
113+
```
114+
115+
The link is `fieldKey` → `controllingFieldKey`: the two strings must match exactly (the checkbox carries `metadata["fieldKey"]`, the dependent field points at it via `metadata["conditional"]["controllingFieldKey"]`). `operator` chooses which checkbox state satisfies the condition — `is_checked` or `is_not_checked`. `action` chooses what happens while the condition is unmet: `show` keeps the dependent field **hidden until met**, while `unlock` renders it **visible but read-only (locked) until met**.
116+
79117
### get_status
80118

81119
```python

0 commit comments

Comments
 (0)