TurboSign PHP SDK
Let an agent scaffold this for you
Install the TurboDocx Quickstart Skill and let Claude Code, Cursor, Copilot, Codex, or any agent that speaks the Agent Skills standard install the SDK, wire it into your app, and write a working TurboSign integration end-to-end.
$npx skills add TurboDocx/quickstart›/turbodocx-sdk turbosignThe official TurboDocx SDK for PHP applications. Build document generation and digital signature workflows with modern PHP 8.1+ features, strong typing, and comprehensive error handling. Available on Packagist as turbodocx/sdk.
Installation
composer require turbodocx/sdk
Requirements
- PHP 8.1 or higher
- Composer
- ext-json
- ext-fileinfo
This SDK leverages PHP 8.1+ features including enums, named parameters, readonly classes, and match expressions for a superior developer experience.
Configuration
- Manual Configuration
- From Environment
<?php
use TurboDocx\TurboSign;
use TurboDocx\Config\HttpClientConfig;
// Configure with all options
TurboSign::configure(new HttpClientConfig(
apiKey: $_ENV['TURBODOCX_API_KEY'], // Required: Your TurboDocx API key
orgId: $_ENV['TURBODOCX_ORG_ID'], // Required: Your organization ID
senderEmail: $_ENV['TURBODOCX_SENDER_EMAIL'], // Required: Reply-to email for signature requests
senderName: $_ENV['TURBODOCX_SENDER_NAME'], // Optional: Sender name (strongly recommended)
baseUrl: 'https://api.turbodocx.com' // Optional: Custom API endpoint
));
<?php
use TurboDocx\TurboSign;
use TurboDocx\Config\HttpClientConfig;
// Auto-configure from environment variables
TurboSign::configure(HttpClientConfig::fromEnvironment());
// Reads from: TURBODOCX_API_KEY, TURBODOCX_ORG_ID,
// TURBODOCX_SENDER_EMAIL, TURBODOCX_SENDER_NAME
The senderEmail parameter is required for TurboSign. This email appears as the reply-to address in signature request emails. If you omit it, configure() throws a ValidationException before any request is sent (unless skipSenderValidation is enabled, which TurboSign does not use).
Environment Variables
# .env
TURBODOCX_API_KEY=your_api_key_here
TURBODOCX_ORG_ID=your_org_id_here
TURBODOCX_SENDER_EMAIL=you@company.com
TURBODOCX_SENDER_NAME=Your Company Name
Both apiKey and orgId parameters are required for all API requests. To get your credentials, follow the Get Your Credentials steps from the SDKs main page.
Quick Start
Send a Document for Signature
<?php
use TurboDocx\TurboSign;
use TurboDocx\Config\HttpClientConfig;
use TurboDocx\Types\Recipient;
use TurboDocx\Types\Field;
use TurboDocx\Types\SignatureFieldType;
use TurboDocx\Types\Requests\SendSignatureRequest;
TurboSign::configure(HttpClientConfig::fromEnvironment());
// Send document with coordinate-based fields
$result = TurboSign::sendSignature(
new SendSignatureRequest(
recipients: [
new Recipient('Alice Smith', 'alice@example.com', 1),
new Recipient('Bob Johnson', 'bob@example.com', 2)
],
fields: [
// Alice's signature
new Field(
type: SignatureFieldType::SIGNATURE,
recipientEmail: 'alice@example.com',
page: 1,
x: 100,
y: 650,
width: 200,
height: 50
),
new Field(
type: SignatureFieldType::DATE,
recipientEmail: 'alice@example.com',
page: 1,
x: 320,
y: 650,
width: 100,
height: 30,
defaultValue: '12/31/2026' // Pins a fixed date in MM/DD/YYYY; omit to auto-fill the signing date
),
// Bob's signature
new Field(
type: SignatureFieldType::SIGNATURE,
recipientEmail: 'bob@example.com',
page: 1,
x: 100,
y: 720,
width: 200,
height: 50
),
new Field(
type: SignatureFieldType::DATE,
recipientEmail: 'bob@example.com',
page: 1,
x: 320,
y: 720,
width: 100,
height: 30
)
],
fileLink: 'https://www.turbodocx.com/examples/turbodocx.pdf',
documentName: 'Service Agreement',
senderName: 'Acme Corp',
senderEmail: 'contracts@acme.com'
)
);
echo "Document ID: {$result->documentId}\n";
The above examples omit error handling for brevity. In production, wrap all TurboSign calls in try-catch blocks. See Error Handling for complete patterns.
Using Template-Based Fields
<?php
use TurboDocx\Types\Recipient;
use TurboDocx\Types\Field;
use TurboDocx\Types\SignatureFieldType;
use TurboDocx\Types\Requests\SendSignatureRequest;
use TurboDocx\Types\TemplateConfig;
use TurboDocx\Types\FieldPlacement;
$result = TurboSign::sendSignature(
new SendSignatureRequest(
recipients: [
new Recipient('Alice Smith', 'alice@example.com', 1)
],
fields: [
new Field(
type: SignatureFieldType::SIGNATURE,
recipientEmail: 'alice@example.com',
template: new TemplateConfig(
anchor: '{SIGNATURE_ALICE}',
placement: FieldPlacement::REPLACE,
size: ['width' => 200, 'height' => 50]
)
),
new Field(
type: SignatureFieldType::DATE,
recipientEmail: 'alice@example.com',
template: new TemplateConfig(
anchor: '{DATE_ALICE}',
placement: FieldPlacement::REPLACE,
size: ['width' => 100, 'height' => 30]
)
)
],
fileLink: 'https://www.turbodocx.com/examples/turbodocx.pdf',
senderName: 'Your Company',
senderEmail: 'sender@company.com'
)
);
The above examples omit error handling for brevity. In production, wrap all TurboSign calls in try-catch blocks. See Error Handling for complete patterns.
Important: The document file must contain the anchor text (e.g., {SIGNATURE_ALICE}, {DATE_ALICE}) that you reference in your fields. If the anchors don't exist in the document, the API will return an error.
File Input Methods
TurboSign supports four different ways to provide document files:
1. File Upload (Direct)
<?php
use TurboDocx\TurboSign;
use TurboDocx\Config\HttpClientConfig;
use TurboDocx\Types\Recipient;
use TurboDocx\Types\Field;
use TurboDocx\Types\SignatureFieldType;
use TurboDocx\Types\Requests\SendSignatureRequest;
TurboSign::configure(HttpClientConfig::fromEnvironment());
$pdfContent = file_get_contents('./contract.pdf');
$result = TurboSign::sendSignature(
new SendSignatureRequest(
file: $pdfContent,
fileName: 'contract.pdf', // Optional
recipients: [
new Recipient('John Doe', 'john@example.com', 1)
],
fields: [
new Field(
type: SignatureFieldType::SIGNATURE,
recipientEmail: 'john@example.com',
page: 1,
x: 100,
y: 500,
width: 200,
height: 50
)
]
)
);
2. File URL
<?php
use TurboDocx\TurboSign;
use TurboDocx\Types\Recipient;
use TurboDocx\Types\Field;
use TurboDocx\Types\SignatureFieldType;
use TurboDocx\Types\Requests\SendSignatureRequest;
$result = TurboSign::sendSignature(
new SendSignatureRequest(
fileLink: 'https://www.turbodocx.com/examples/turbodocx.pdf',
recipients: [
new Recipient('John Doe', 'john@example.com', 1)
],
fields: [
new Field(
type: SignatureFieldType::SIGNATURE,
recipientEmail: 'john@example.com',
page: 1,
x: 100,
y: 500,
width: 200,
height: 50
)
]
)
);
Use fileLink when your documents are already hosted on cloud storage (S3, Google Cloud Storage, etc.). This is more efficient than downloading and re-uploading files.
3. TurboDocx Deliverable ID
<?php
use TurboDocx\TurboSign;
use TurboDocx\Types\Recipient;
use TurboDocx\Types\Field;
use TurboDocx\Types\SignatureFieldType;
use TurboDocx\Types\Requests\SendSignatureRequest;
// Use a previously generated TurboDocx document
$result = TurboSign::sendSignature(
new SendSignatureRequest(
deliverableId: 'deliverable-uuid-from-turbodocx',
recipients: [
new Recipient('John Doe', 'john@example.com', 1)
],
fields: [
new Field(
type: SignatureFieldType::SIGNATURE,
recipientEmail: 'john@example.com',
page: 1,
x: 100,
y: 500,
width: 200,
height: 50
)
]
)
);
deliverableId references documents generated using TurboDocx's document generation API. This creates a seamless workflow: generate → sign.
4. TurboDocx Template ID
<?php
use TurboDocx\TurboSign;
use TurboDocx\Types\Recipient;
use TurboDocx\Types\Field;
use TurboDocx\Types\SignatureFieldType;
use TurboDocx\Types\Requests\SendSignatureRequest;
use TurboDocx\Types\TemplateConfig;
use TurboDocx\Types\FieldPlacement;
// Use a pre-configured TurboSign template
$result = TurboSign::sendSignature(
new SendSignatureRequest(
templateId: 'template-uuid-from-turbodocx',
recipients: [
new Recipient('Alice Smith', 'alice@example.com', 1)
],
fields: [
new Field(
type: SignatureFieldType::SIGNATURE,
recipientEmail: 'alice@example.com',
template: new TemplateConfig(
anchor: '{SIGNATURE_ALICE}',
placement: FieldPlacement::REPLACE,
size: ['width' => 200, 'height' => 50]
)
)
]
)
);
templateId references pre-configured TurboSign templates created in the TurboDocx dashboard. These templates come with built-in anchors and field positioning, making it easy to reuse signature workflows across multiple documents.
API Reference
Configure
Configure the SDK with your API credentials and organization settings.
use TurboDocx\TurboSign;
use TurboDocx\Config\HttpClientConfig;
// Manual configuration
TurboSign::configure(new HttpClientConfig(
apiKey: 'your-api-key',
orgId: 'your-org-id',
senderEmail: 'you@company.com',
senderName: 'Your Company'
));
// Or from environment
TurboSign::configure(HttpClientConfig::fromEnvironment());
Prepare for review
Upload a document for preview without sending signature request emails.
use TurboDocx\Types\Recipient;
use TurboDocx\Types\Field;
use TurboDocx\Types\SignatureFieldType;
use TurboDocx\Types\Requests\CreateSignatureReviewLinkRequest;
$result = TurboSign::createSignatureReviewLink(
new CreateSignatureReviewLinkRequest(
recipients: [
new Recipient('John Doe', 'john@example.com', 1)
],
fields: [
new Field(
type: SignatureFieldType::SIGNATURE,
recipientEmail: 'john@example.com',
page: 1,
x: 100,
y: 500,
width: 200,
height: 50
)
],
fileLink: 'https://www.turbodocx.com/examples/turbodocx.pdf',
documentName: 'Contract Draft'
)
);
echo "Preview URL: {$result->previewUrl}\n";
echo "Document ID: {$result->documentId}\n";
Prepare for signing
Upload a document and immediately send signature requests to all recipients.
use TurboDocx\Types\Recipient;
use TurboDocx\Types\Field;
use TurboDocx\Types\SignatureFieldType;
use TurboDocx\Types\Requests\SendSignatureRequest;
$result = TurboSign::sendSignature(
new SendSignatureRequest(
recipients: [
new Recipient('Recipient Name', 'recipient@example.com', 1)
],
fields: [
new Field(
type: SignatureFieldType::SIGNATURE,
recipientEmail: 'recipient@example.com',
page: 1,
x: 100,
y: 500,
width: 200,
height: 50
)
],
fileLink: 'https://www.turbodocx.com/examples/turbodocx.pdf',
documentName: 'Service Agreement'
)
);
echo "Document ID: {$result->documentId}\n";
Reminders and expiration
sendSignature can also schedule automatic reminder emails and an expiration deadline. All eight
schedule fields are optional and both features are off by default, so omitting them preserves
the original send behavior. The resolved schedule is frozen onto the document when it is sent:
changing your org defaults later never alters a document already out for signature.
use TurboDocx\Types\Requests\SendSignatureRequest;
$result = TurboSign::sendSignature(
new SendSignatureRequest(
// ...recipients, fields, fileLink, documentName
remindersEnabled: true,
reminderDelay: ['value' => 3, 'unit' => 'days'], // time to the FIRST reminder
reminderInterval: ['value' => 3, 'unit' => 'days'], // gap between later reminders
maxReminders: 5, // -1 unlimited, 0 none, max 50 (default 5)
expirationEnabled: true,
expireAfter: ['value' => 30, 'unit' => 'days'], // how long the document stays signable
expirationWarning: ['value' => 3, 'unit' => 'days'], // 0 = never warn
expirationWarningInterval: ['value' => 1, 'unit' => 'days']
)
);
Durations are ['value' => N, 'unit' => 'hours'|'days'] objects. value is a whole number from
1 up to a maximum of 999 days (23976 hours); expirationWarning also accepts 0 to disable
warnings. maxReminders accepts -1 (unlimited), 0 (none), or any value up to 50. The resulting
deadline is readable afterwards via getStatus()->expiresAt.
Send a reminder
Send a standalone reminder to whoever's turn it is to sign
(POST /turbosign/documents/{documentId}/send-reminder). It is independent of the automatic
cadence: it works even when reminders are disabled or the per-signer cap is already spent, does
not consume that cap, and only emails signers at the current signing order. Pass null (or
omit the argument) to remind everyone eligible; do not pass an empty array, which the API rejects.
// Remind everyone whose turn it is to sign.
$result = TurboSign::sendReminder('document-uuid');
foreach ($result['results'] as $r) {
// 'sent', 'skipped_wrong_order', 'skipped_completed', ...
echo "{$r['recipientId']}: {$r['status']}\n";
}
// Or limit to specific recipients (all-or-nothing): every id must be a current-order pending signer.
TurboSign::sendReminder('document-uuid', ['recipient-uuid-1', 'recipient-uuid-2']);
Get status
Retrieve the current status of a document. When expiration is enabled, the response also carries the signing-window deadline as expiresAt; once that instant passes the document reaches the terminal expired status. The same expiresAt is available on the document returned by getRecipients(). For per-signer detail, use Get recipients.
$status = TurboSign::getStatus('document-uuid');
echo "Document Status: {$status->status}\n"; // 'under_review', 'completed', 'voided', 'expired'
// expiresAt is the signing-window deadline (ISO 8601), or null when expiration is off.
echo "Expires: " . ($status->expiresAt ?? 'never') . "\n";
Get recipients
See who the document went to, who has signed, who you are still waiting on, and who sent it.
$progress = TurboSign::getRecipients('document-uuid');
echo "{$progress->summary->completed}/{$progress->summary->total} signed, ";
echo "waiting on {$progress->summary->waitingOn}\n";
foreach ($progress->recipients as $r) {
echo " {$r->name} <{$r->email}>: {$r->effectiveStatus}";
echo " (emailed {$r->delivery->totalSent}x)\n";
}
status is the raw database value and is only ever pending, viewed or completed.
effectiveStatus layers the document's outcome on top, adding voided and expired: that
is the one to display.
On a voided or expired document an unsigned signer still reads pending in status, so
branching on it would show someone as "still to sign" when their signing link is already dead.
A completed signature is never revoked: someone who signed before the document was voided
still reads completed.
summary counts by effectiveStatus, and waitingOn (pending + viewed) drops to zero once
the document is terminal.
Each recipient also carries a delivery block: firstSentOn, lastSentOn, totalSent,
reminderCount, lastRemindedAt, warningCount, lastWarningAt. It counts the signature
request, resends, reminders, expiry warnings and terminal notices; CC notifications are
excluded, since a CC address is not a signer.
reminderCount and lastRemindedAt do not mean what their names suggestreminderCount counts automatic (scheduled) reminders only: the counter maxReminders
caps. A manual "remind now" is a standalone nudge that must not consume the cap budget, so it
does not increment this, even though the email it sends does appear in totalSent.
lastRemindedAt is a cadence clock, not a record of a reminder: the initial
signature-request send, each scheduled reminder, each manual "remind now" and each expiry
warning all stamp it. Only scheduled reminders bump reminderCount.
So a freshly-sent document returns a non-null lastRemindedAt equal to the invitation
timestamp alongside reminderCount: 0: nobody has been reminded. To answer "have we actually
chased this person", read totalSent, not reminderCount.
warningCount / lastWarningAt have no such caveat.
Download document
Download the completed signed document as PDF content.
$pdfContent = TurboSign::download('document-uuid');
// Save to file
file_put_contents('signed-contract.pdf', $pdfContent);
// Or send as HTTP response
header('Content-Type: application/pdf');
header('Content-Disposition: attachment; filename="signed.pdf"');
echo $pdfContent;
Void
Cancel/void a signature request that hasn't been completed.
use TurboDocx\Types\Responses\VoidDocumentResponse;
$result = TurboSign::void('document-uuid', 'Document needs to be revised');
echo "Document ID: {$result->id}\n";
echo "Status: {$result->status}\n";
echo "Void Reason: {$result->voidReason}\n";
Resend
Resend signature request emails to specific recipients.
// Resend to specific recipients
$result = TurboSign::resend('document-uuid', ['recipient-id-1', 'recipient-id-2']);
// Resend to all recipients
$result = TurboSign::resend('document-uuid', []);
echo "Recipients notified: {$result->recipientCount}\n";
Get audit trail
Retrieve the complete audit trail for a document, including all events and actions.
$audit = TurboSign::getAuditTrail('document-uuid');
echo "Audit Trail:\n";
foreach ($audit->auditTrail as $entry) {
echo " {$entry->timestamp} - {$entry->actionType}";
if ($entry->user) {
echo " by {$entry->user->name}";
}
echo "\n";
}
Field Types
TurboSign supports 11 different field types using PHP enums:
use TurboDocx\Types\SignatureFieldType;
SignatureFieldType::SIGNATURE // Signature field
SignatureFieldType::INITIAL // Initial field
SignatureFieldType::DATE // Date stamp (auto-filled when signed)
SignatureFieldType::TEXT // Free text input
SignatureFieldType::FULL_NAME // Full name (auto-filled from recipient)
SignatureFieldType::FIRST_NAME // First name
SignatureFieldType::LAST_NAME // Last name
SignatureFieldType::EMAIL // Email address
SignatureFieldType::TITLE // Job title
SignatureFieldType::COMPANY // Company name
SignatureFieldType::CHECKBOX // Checkbox field
Field Positioning
TurboSign supports two ways to position fields:
1. Coordinate-Based (Pixel Perfect)
new Field(
type: SignatureFieldType::SIGNATURE,
recipientEmail: 'john@example.com',
page: 1, // Page number (1-indexed)
x: 100, // X coordinate
y: 500, // Y coordinate
width: 200, // Width in pixels
height: 50 // Height in pixels
)
2. Template Anchors (Dynamic)
use TurboDocx\Types\TemplateConfig;
use TurboDocx\Types\FieldPlacement;
new Field(
type: SignatureFieldType::SIGNATURE,
recipientEmail: 'john@example.com',
template: new TemplateConfig(
anchor: '{signature1}', // Text to find in PDF
placement: FieldPlacement::REPLACE, // How to place the field
size: ['width' => 100, 'height' => 30]
)
)
Placement Options:
FieldPlacement::REPLACE- Replace the anchor textFieldPlacement::BEFORE- Place before the anchorFieldPlacement::AFTER- Place after the anchorFieldPlacement::ABOVE- Place above the anchorFieldPlacement::BELOW- Place below the anchor
Advanced Field Options
// Checkbox (pre-checked, readonly)
new Field(
type: SignatureFieldType::CHECKBOX,
recipientEmail: 'john@example.com',
page: 1,
x: 100,
y: 600,
width: 20,
height: 20,
defaultValue: 'true', // Pre-checked
isReadonly: true // Cannot be unchecked
)
// Multiline text field
new Field(
type: SignatureFieldType::TEXT,
recipientEmail: 'john@example.com',
page: 1,
x: 100,
y: 200,
width: 400,
height: 100,
isMultiline: true, // Allow multiple lines
required: true, // Field is required
backgroundColor: '#f0f0f0' // Background color
)
// Readonly text (pre-filled, non-editable)
new Field(
type: SignatureFieldType::TEXT,
recipientEmail: 'john@example.com',
page: 1,
x: 100,
y: 300,
width: 300,
height: 30,
defaultValue: 'This text is pre-filled',
isReadonly: true
)
Conditional (IF/THEN) Fields
The optional metadata builds IF/THEN relationships between fields. Put a fieldKey on a
controlling checkbox, then point each dependent field's controllingFieldKey back at it.
use TurboDocx\Types\FieldMetadata;
use TurboDocx\Types\FieldConditional;
use TurboDocx\Types\ConditionalOperator;
use TurboDocx\Types\ConditionalAction;
// Controlling checkbox, carries a stable fieldKey
new Field(
type: SignatureFieldType::CHECKBOX,
recipientEmail: 'reviewer@company.com',
page: 1,
x: 100,
y: 400,
width: 20,
height: 20,
metadata: new FieldMetadata(fieldKey: 'request_changes')
);
// Dependent text field, hidden until the checkbox is checked
new Field(
type: SignatureFieldType::TEXT,
recipientEmail: 'reviewer@company.com',
page: 1,
x: 130,
y: 400,
width: 300,
height: 60,
metadata: new FieldMetadata(
conditional: new FieldConditional(
controllingFieldKey: 'request_changes', // = the checkbox's fieldKey
operator: ConditionalOperator::IS_CHECKED, // ::IS_CHECKED | ::IS_NOT_CHECKED
action: ConditionalAction::SHOW // ::SHOW | ::UNLOCK
)
)
);
Use action: 'unlock' to keep a field visible but read-only until the box is checked. A
malformed rule returns 400 InvalidConditionalRule; a well-formed rule whose
controllingFieldKey matches no checkbox fails open (the field stays visible/editable). See
Conditional (IF/THEN) Fields.
Error Handling
Every typed exception extends TurboDocxException, itself a plain Exception subclass with two extra readonly properties: statusCode (int, HTTP status) and errorCode (string, e.g. 'VALIDATION_ERROR'). Because the constructor hardcodes PHP's built-in Exception::getCode() to 0, read $e->errorCode, not $e->getCode(), for the machine-readable reason:
use TurboDocx\Exceptions\AuthenticationException;
use TurboDocx\Exceptions\AuthorizationException;
use TurboDocx\Exceptions\ValidationException;
use TurboDocx\Exceptions\NotFoundException;
use TurboDocx\Exceptions\ConflictException;
use TurboDocx\Exceptions\RateLimitException;
use TurboDocx\Exceptions\NetworkException;
try {
$result = TurboSign::sendSignature(/* ... */);
} catch (AuthenticationException $e) {
// 401 - Invalid API key or access token
echo "Authentication failed: {$e->getMessage()}\n";
} catch (AuthorizationException $e) {
// 403 - Valid credentials without permission for this operation
echo "Authorization error: {$e->getMessage()}\n";
} catch (ValidationException $e) {
// 400 - Invalid request data
echo "Validation error: {$e->getMessage()}\n";
} catch (NotFoundException $e) {
// 404 - Document not found
echo "Not found: {$e->getMessage()}\n";
} catch (ConflictException $e) {
// 409 - Conflicts with the current resource state
echo "Conflict: {$e->getMessage()}\n";
} catch (RateLimitException $e) {
// 429 - Rate limit exceeded
echo "Rate limit: {$e->getMessage()}\n";
} catch (NetworkException $e) {
// Network/connection error
echo "Network error: {$e->getMessage()}\n";
} catch (TurboDocxException $e) {
// Catch-all: read the machine-readable reason from errorCode, not getCode()
echo "Error {$e->errorCode}: {$e->getMessage()} (status {$e->statusCode})\n";
}
Error Classes
| Error Class | Status Code | Description |
|---|---|---|
TurboDocxException | varies | Base exception for all SDK errors |
AuthenticationException | 401 | Invalid or missing API credentials |
AuthorizationException | 403 | Valid credentials without permission for this operation |
ValidationException | 400 | Invalid request parameters |
NotFoundException | 404 | Document or resource not found |
ConflictException | 409 | Request conflicts with current resource state |
RateLimitException | 429 | Too many requests |
NetworkException | - | Network connectivity issues |
All exceptions extend TurboDocxException and include:
getMessage()- Human-readable error messagestatusCode- HTTP status code, a public readonly?int(null forNetworkException)errorCode- Error code string (e.g.,'AUTHENTICATION_ERROR'), a public readonly?string
PHP Types
Enums
The SDK uses PHP 8.1+ enums for type safety:
// Field types
enum SignatureFieldType: string {
case SIGNATURE = 'signature';
case INITIAL = 'initial';
case DATE = 'date';
case TEXT = 'text';
case FULL_NAME = 'full_name';
case FIRST_NAME = 'first_name';
case LAST_NAME = 'last_name';
case EMAIL = 'email';
case TITLE = 'title';
case COMPANY = 'company';
case CHECKBOX = 'checkbox';
}
// Field placement
enum FieldPlacement: string {
case REPLACE = 'replace';
case BEFORE = 'before';
case AFTER = 'after';
case ABOVE = 'above';
case BELOW = 'below';
}
// Document status
enum DocumentStatus: string {
case DRAFT = 'draft';
case SETUP_COMPLETE = 'setup_complete';
case REVIEW_READY = 'review_ready';
case UNDER_REVIEW = 'under_review';
case COMPLETED = 'completed';
case VOIDED = 'voided';
}
// Conditional (IF/THEN) operator, the condition evaluated against the controlling checkbox
enum ConditionalOperator: string {
case IS_CHECKED = 'is_checked';
case IS_NOT_CHECKED = 'is_not_checked';
}
// Conditional (IF/THEN) action, what happens to the dependent field until the condition is met
enum ConditionalAction: string {
case SHOW = 'show'; // hidden until met
case UNLOCK = 'unlock'; // visible but read-only until met
}
Readonly Classes
The SDK uses readonly classes with typed properties:
final class Recipient {
public function __construct(
public string $name,
public string $email,
public int $signingOrder
) {}
}
final class Field {
public function __construct(
public SignatureFieldType $type,
public string $recipientEmail,
public ?int $page = null,
public ?int $x = null,
public ?int $y = null,
public ?int $width = null,
public ?int $height = null,
public ?TemplateConfig $template = null,
public ?string $defaultValue = null, // checkbox: 'true'/'false'; date: a fixed MM/DD/YYYY (omit to auto-fill the signing date)
public bool $isMultiline = false,
public bool $isReadonly = false,
public bool $required = false,
public ?string $backgroundColor = null,
public ?FieldMetadata $metadata = null // Conditional (IF/THEN) metadata
) {}
}
// Conditional (IF/THEN) metadata
final class FieldMetadata {
public function __construct(
public ?string $fieldKey = null, // On a controlling checkbox
public ?FieldConditional $conditional = null // On a dependent field
) {}
}
final class FieldConditional {
public function __construct(
public string $controllingFieldKey, // = the checkbox's fieldKey (non-empty)
public ConditionalOperator $operator, // ConditionalOperator::IS_CHECKED | ::IS_NOT_CHECKED
public ConditionalAction $action // ConditionalAction::SHOW | ::UNLOCK
) {}
}
Request Objects
final class SendSignatureRequest {
public function __construct(
public array $recipients, // Recipient[]
public array $fields, // Field[]
public ?string $file = null,
public ?string $fileName = null,
public ?string $fileLink = null,
public ?string $deliverableId = null,
public ?string $templateId = null,
public ?string $documentName = null,
public ?string $documentDescription = null,
public ?string $senderName = null,
public ?string $senderEmail = null,
public ?array $ccEmails = null
) {}
}
Exactly one file source is required: file, fileLink, deliverableId, or templateId.
Additional Documentation
For detailed information about advanced configuration and API concepts, see:
Core API References
- Request Body Reference - Complete request body parameters, file sources, and multipart/form-data structure
- Recipients Reference - Recipient properties, signing order, metadata, and configuration options
- Field Types Reference - All available field types (signature, date, text, checkbox, etc.) with properties and behaviors
- Field Positioning Methods - Template-based vs coordinate-based positioning, anchor configuration, and best practices