Workflow Mode
Integrate Visiono into external workflows with secure signed URLs.
Overview
Workflow Mode allows external systems to embed Visiono photo collection seamlessly into their processes. Users are redirected from external systems (like Zendesk tickets or CRM records) to Visiono, complete photo uploads, and are automatically redirected back with verified data.
Key Features
| Feature | Description |
|---|---|
| Signed URLs | HMAC-SHA256 signature prevents tampering |
| Auto-redirect | Return to external system after completion |
| Hidden Fields | Pre-filled data not visible to users |
| Per-submission Tracking | External source and reference stored |
| Signature Verification | Verify redirect data wasn't modified |
How It Works
sequenceDiagram
participant E as External System
participant V as Visiono
participant U as User
E->>E: Generate signed URL
E->>U: Send link to user
U->>V: Open signed URL
V->>V: Validate signature
V->>U: Show photo upload
U->>V: Upload photos
V->>E: Redirect with signature
E->>E: Validate return signatureConfiguration
1. Enable Workflow Mode
- Navigate to your Permanent Link
- Click Edit
- Expand Workflow Mode section
- Enable Workflow Mode toggle
- Configure redirect URL
- Copy the Workflow Secret
2. Configure Redirect URL
Set the URL users return to after completing uploads:
https://your-system.com/done?id={submission_id}&ref={reference}&sig={signature}Available Placeholders
| Placeholder | Description | Example |
|---|---|---|
{submission_id} | Visiono submission ID | pls_123 |
{unique_value} | Unique field value passed | ABC123 |
{reference} | External reference passed | ticket-456 |
{photo_count} | Number of photos uploaded | 5 |
{timestamp} | Unix timestamp | 1705500000 |
{signature} | HMAC signature for verification | abc123... |
Generating Signed URLs
URL Parameters
| Param | Long Name | Description | Required |
|---|---|---|---|
uv | unique_value | Unique identifier | Yes |
src | source | Source system | Yes |
ref | reference | External reference | Yes |
ts | timestamp | Unix timestamp | Yes |
sig | signature | HMAC-SHA256 signature | Yes |
Signature Algorithm
payload = "{unique_value}|{source}|{reference}|{timestamp}"
signature = HMAC-SHA256(payload, workflow_secret)PHP Example
<?php
$workflowSecret = 'your-workflow-secret';
$slug = 'damage-report';
// Data
$uniqueValue = 'ABC123';
$source = 'zendesk';
$reference = 'ticket-456';
$timestamp = time();
// Generate signature
$payload = "{$uniqueValue}|{$source}|{$reference}|{$timestamp}";
$signature = hash_hmac('sha256', $payload, $workflowSecret);
// Build URL
$baseUrl = "https://visiono.io/s/{$slug}";
$params = http_build_query([
'uv' => $uniqueValue,
'src' => $source,
'ref' => $reference,
'ts' => $timestamp,
'sig' => $signature,
]);
$url = "{$baseUrl}?{$params}";
// https://visiono.io/s/damage-report?uv=ABC123&src=zendesk&ref=ticket-456&ts=1705500000&sig=abc123...JavaScript Example
const crypto = require('crypto');
const workflowSecret = 'your-workflow-secret';
const slug = 'damage-report';
// Data
const uniqueValue = 'ABC123';
const source = 'zendesk';
const reference = 'ticket-456';
const timestamp = Math.floor(Date.now() / 1000);
// Generate signature
const payload = `${uniqueValue}|${source}|${reference}|${timestamp}`;
const signature = crypto
.createHmac('sha256', workflowSecret)
.update(payload)
.digest('hex');
// Build URL
const params = new URLSearchParams({
uv: uniqueValue,
src: source,
ref: reference,
ts: timestamp,
sig: signature,
});
const url = `https://visiono.io/s/${slug}?${params}`;Python Example
import hmac
import hashlib
import time
from urllib.parse import urlencode
workflow_secret = 'your-workflow-secret'
slug = 'damage-report'
# Data
unique_value = 'ABC123'
source = 'zendesk'
reference = 'ticket-456'
timestamp = int(time.time())
# Generate signature
payload = f"{unique_value}|{source}|{reference}|{timestamp}"
signature = hmac.new(
workflow_secret.encode(),
payload.encode(),
hashlib.sha256
).hexdigest()
# Build URL
params = urlencode({
'uv': unique_value,
'src': source,
'ref': reference,
'ts': timestamp,
'sig': signature,
})
url = f"https://visiono.io/s/{slug}?{params}"Validating Redirect Signature
When users are redirected back, verify the signature to ensure data integrity.
Return URL Example
https://your-system.com/done?sub=pls_123&ref=ticket-456&cnt=5&ts=1705500100&sig=def456...Signature Verification
The return signature is computed as:
payload = "{submission_id}|{unique_value}|{reference}|{photo_count}|{timestamp}"
expected_signature = HMAC-SHA256(payload, workflow_secret)PHP Verification
<?php
$workflowSecret = 'your-workflow-secret';
// Get parameters from redirect
$submissionId = $_GET['sub'];
$uniqueValue = $_GET['uv'];
$reference = $_GET['ref'];
$photoCount = $_GET['cnt'];
$timestamp = $_GET['ts'];
$receivedSignature = $_GET['sig'];
// Verify signature
$payload = "{$submissionId}|{$uniqueValue}|{$reference}|{$photoCount}|{$timestamp}";
$expectedSignature = hash_hmac('sha256', $payload, $workflowSecret);
if (hash_equals($expectedSignature, $receivedSignature)) {
// Signature valid - process the submission
echo "Photos submitted successfully!";
} else {
// Signature invalid - reject
http_response_code(400);
echo "Invalid signature";
}Link Expiration
Signed URLs expire after 1 hour by default. This prevents:
- Old links from being reused
- Replay attacks
- Stale data
If a user opens an expired link, they see an "Link Expired" error page.
Security Best Practices
Protect Your Secret
- Store the workflow secret securely
- Never expose it in client-side code
- Rotate secrets periodically
- Use environment variables
Validate Timestamps
$maxAge = 3600; // 1 hour
if (time() - $timestamp > $maxAge) {
// Link expired
return false;
}Use HTTPS
Always use HTTPS for:
- Your redirect URLs
- Any API calls
- Webhook endpoints
Error Pages
Users may see error pages for:
| Error | Cause | Solution |
|---|---|---|
| Missing Parameters | URL lacks required params | Check URL generation |
| Invalid Signature | Signature doesn't match | Verify secret and algorithm |
| Link Expired | Timestamp > 1 hour old | Generate new link |
Webhook Integration
Workflow Mode works with webhooks. The submission.created event includes:
{
"event": "submission.created",
"data": {
"photo_request": {
"id": "pr_123",
"custom_slug": "damage-report"
},
"permanent_link_submission": {
"id": "pls_456",
"unique_field_value": "ABC123",
"external_source": "zendesk",
"external_reference": "ticket-456"
}
}
}Use Cases
Zendesk Ticket Photos
- Agent sends customer signed link
- Customer uploads damage photos
- Customer redirected back to ticket
- Webhook updates ticket with photos
Insurance Claims
- Claim system generates signed link
- Policyholder documents damage
- Redirected to claim confirmation
- Photos automatically linked to claim
Field Service
- Technician receives work order
- Opens signed link from mobile
- Documents completed work
- Redirected to job completion page
Troubleshooting
Signature Mismatch
- Verify secret matches exactly
- Check parameter encoding
- Confirm timestamp format
- Ensure payload order is correct
Redirect Not Working
- Verify redirect URL is configured
- Check placeholder syntax
- Confirm URL is properly encoded
Link Expired Immediately
- Check server time synchronization
- Verify timestamp is Unix format
- Ensure timestamp is current
Related Resources
- Permanent Links - Link configuration
- Webhooks - Event notifications
- API Reference - Full API documentation
