External Participants
External Participants enable customer stakeholders to participate in AI-driven processes without requiring full platform accounts, using secure magic link authentication.
Why External Participants?
Enterprise deployments involve people outside your organization:
- Customer IT Admins - Approve SSO configurations
- Customer CISOs - Sign off on security reviews
- Customer HR Managers - Validate SCIM user mappings
- Partners - Review integration configurations
External participants need:
- Secure access without creating accounts
- Limited, scoped permissions
- Clear audit trail
- Easy approval workflows
How It Works
┌─────────────────────────────────────────────────────────────┐
│ Process Instance │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1. Agent reaches approval gate │
│ │ │
│ ▼ │
│ 2. System generates magic link │
│ │ │
│ ▼ │
│ 3. Email sent to external participant │
│ │ │
│ ▼ │
│ 4. Participant clicks link → lands on approval portal │
│ │ │
│ ▼ │
│ 5. Reviews context, artifacts, makes decision │
│ │ │
│ ▼ │
│ 6. Decision recorded, process continues │
│ │
└─────────────────────────────────────────────────────────────┘
Magic Link Authentication
Generate Magic Link
const magicLink = await client.processes.createExternalParticipantLink({
processInstanceId: 'proc-inst-123',
participantId: 'customer_it_admin',
email: 'admin@customer.com',
name: 'John Smith',
expiresIn: '7d',
permissions: ['view', 'approve', 'comment']
})
// Returns:
// {
// url: 'https://app.meetloyd.com/external/p/proc-inst-123?token=eyJhbGc...',
// token: 'eyJhbGc...',
// expiresAt: '2024-01-22T10:00:00Z'
// }
Magic Link Email
await client.processes.sendParticipantInvite({
processInstanceId: 'proc-inst-123',
participantId: 'customer_it_admin',
email: 'admin@customer.com',
subject: 'SSO Configuration Review Required',
customMessage: 'Please review the SSO configuration for your Okta integration.'
})
Email template:
Subject: SSO Configuration Review Required - Acme Corp Deployment
Hi John,
You have been invited to review the SSO configuration for the
Acme Corp deployment.
[Review Configuration] <-- Magic link button
Your approval is required to proceed with the deployment.
This link expires in 7 days.
---
MeetLoyd Enterprise Deployment Team
Participant Portal
External participants access a secure, limited portal:
Portal Features
┌─────────────────────────────────────────────────────────────┐
│ Enterprise SSO Deployment - Acme Corp │
│ Status: Awaiting Your Approval │
├─────────────────────────────────────────────────────────────┤
│ │
│ 📋 Current Phase: Configuration │
│ ⏱️ Started: Jan 15, 2024 │
│ 📊 Progress: 45% │
│ │
├─────────────────────────────────────────────────────────────┤
│ Pending Approval │
│ ───────────────── │
│ SSO Configuration Review │
│ │
│ Please review the following configuration: │
│ │
│ 📄 SSO Configuration Summary │
│ 📄 Attribute Mapping Document │
│ 📄 Test Results │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Comments (optional) │ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ [Approve] [Request Changes] [Reject] │
│ │
├─────────────────────────────────────────────────────────────┤
│ Activity History │
│ ───────────────── │
│ Jan 18 - SSO configuration completed by SSO Agent │
│ Jan 17 - Requirements gathered │
│ Jan 15 - Deployment started │
│ │
└─────────────────────────────────────────────────────────────┘
Portal Permissions
| Permission | Description |
|---|---|
view | View process status and artifacts |
approve | Approve pending approval requests |
reject | Reject and provide feedback |
comment | Add comments to the process |
upload | Upload additional documents |
Defining External Participants
In Process Definition
const processDefinition: ProcessDefinition = {
// ...
humans: {
customer_it_admin: {
id: 'customer_it_admin',
name: 'Customer IT Administrator',
role: 'approver',
raidRole: 'approver',
description: 'Customer IT team member responsible for SSO configuration',
requiredApprovals: [
'sso_config_review',
'scim_provisioning_review',
'production_deployment'
],
notificationPreferences: {
email: true,
reminderIntervals: ['24h', '48h']
}
},
customer_ciso: {
id: 'customer_ciso',
name: 'Customer CISO',
role: 'approver',
raidRole: 'approver',
description: 'Security executive for final security sign-off',
requiredApprovals: [
'security_review',
'compliance_sign_off'
]
},
customer_hr_manager: {
id: 'customer_hr_manager',
name: 'Customer HR Manager',
role: 'informed',
raidRole: 'informed',
description: 'HR manager who needs visibility into user provisioning',
notifications: ['user_provisioning_complete', 'group_mapping_complete']
}
}
}
Assign to Process Instance
const instance = await client.processes.start({
processId: 'enterprise_sso_deployment',
name: 'Acme Corp SSO Deployment',
externalParticipants: [
{
participantId: 'customer_it_admin',
email: 'john.smith@acme.com',
name: 'John Smith',
title: 'Senior IT Administrator'
},
{
participantId: 'customer_ciso',
email: 'jane.doe@acme.com',
name: 'Jane Doe',
title: 'Chief Information Security Officer'
},
{
participantId: 'customer_hr_manager',
email: 'bob.johnson@acme.com',
name: 'Bob Johnson',
title: 'HR Director'
}
]
})
Approval Workflows
Request Approval
Agents request approval when reaching gates:
// Agent requests approval
await client.processes.requestApproval('proc-inst-123', {
taskId: 'sso_config_review',
title: 'SSO Configuration Review',
description: 'Please review the SSO configuration before we proceed to testing.',
approverIds: ['customer_it_admin'],
artifacts: [
{
name: 'SSO Configuration Summary',
key: 'sso_config_summary',
type: 'document'
},
{
name: 'Test Results',
key: 'sso_test_results',
type: 'report'
}
],
context: {
idpType: 'okta',
configuredAttributes: ['email', 'firstName', 'lastName', 'department'],
testStatus: 'passed'
},
expiresIn: '48h',
reminderAt: ['24h']
})
Handle Approval Response
// Listen for approval responses
client.processes.onApprovalResponse('proc-inst-123', (response) => {
if (response.approved) {
console.log('Approval received:', {
taskId: response.taskId,
approver: response.approverEmail,
timestamp: response.timestamp,
comments: response.comments
})
// Process continues automatically
} else if (response.status === 'changes_requested') {
console.log('Changes requested:', {
feedback: response.feedback,
requestedChanges: response.requestedChanges
})
// Notify agents to make changes
} else if (response.status === 'rejected') {
console.log('Approval rejected:', {
reason: response.reason
})
// Handle rejection
}
})
Approval States
┌─────────────┐
│ pending │
└──────┬──────┘
│
┌─────────────────┼─────────────────┐
▼ ▼ ▼
┌───────────┐ ┌─────────────┐ ┌──────────┐
│ approved │ │ changes_ │ │ rejected │
└───────────┘ │ requested │ └──────────┘
└──────┬──────┘
│
▼
┌─────────────┐
│ pending │ (after changes)
└─────────────┘
Notifications
Email Notifications
// Configure notification preferences
await client.processes.updateParticipantPreferences('proc-inst-123', {
participantId: 'customer_it_admin',
preferences: {
email: {
enabled: true,
frequency: 'immediate', // 'immediate' | 'daily_digest' | 'weekly'
types: ['approval_required', 'status_update', 'completion']
},
reminders: {
enabled: true,
intervals: ['24h', '48h'],
escalateAfter: '72h'
}
}
})
Notification Types
| Type | Description | Trigger |
|---|---|---|
approval_required | New approval pending | Approval request created |
reminder | Approval reminder | Based on configured intervals |
escalation | Escalated to backup | Timeout reached |
status_update | Phase completed | Phase transition |
completion | Process completed | All phases done |
Custom Email Templates
await client.processes.setEmailTemplate({
processId: 'enterprise_sso_deployment',
templateType: 'approval_required',
template: {
subject: '{{process_name}} - Your Approval Required',
body: `
Hi {{participant_name}},
{{#if urgent}}
URGENT: Your approval is needed for {{task_title}}.
{{else}}
Your approval is needed for {{task_title}}.
{{/if}}
Process: {{process_name}}
Phase: {{current_phase}}
{{task_description}}
[Review and Approve]({{approval_link}})
This approval is due by {{due_date}}.
Best regards,
{{company_name}} Team
`
}
})
Security
Token Security
Magic link tokens are:
- Single-use per session
- Time-limited (configurable expiration)
- Scoped to specific process and participant
- Revocable at any time
// Revoke a participant's access
await client.processes.revokeParticipantAccess('proc-inst-123', {
participantId: 'customer_it_admin',
reason: 'Contact changed'
})
// Generate new link for replacement contact
const newLink = await client.processes.createExternalParticipantLink({
processInstanceId: 'proc-inst-123',
participantId: 'customer_it_admin',
email: 'new.admin@customer.com',
name: 'New Admin'
})
Access Logging
All external participant actions are logged:
const accessLog = await client.processes.getParticipantAccessLog('proc-inst-123', {
participantId: 'customer_it_admin',
limit: 50
})
for (const entry of accessLog.entries) {
console.log({
timestamp: entry.timestamp,
action: entry.action, // 'link_accessed', 'artifact_viewed', 'approval_submitted'
ipAddress: entry.ipAddress,
userAgent: entry.userAgent,
details: entry.details
})
}
IP Restrictions
Optionally restrict access by IP:
await client.processes.setParticipantRestrictions('proc-inst-123', {
participantId: 'customer_ciso',
restrictions: {
allowedIpRanges: ['10.0.0.0/8', '192.168.1.0/24'],
requireMfa: true,
maxSessions: 1
}
})
API Reference
Participant Endpoints
| Endpoint | Method | Description |
|---|---|---|
/api/processes/:id/participants | GET | List participants |
/api/processes/:id/participants | POST | Add participant |
/api/processes/:id/participants/:pid/link | POST | Generate magic link |
/api/processes/:id/participants/:pid/invite | POST | Send invite email |
/api/processes/:id/participants/:pid/revoke | POST | Revoke access |
External Portal Endpoints
| Endpoint | Method | Description |
|---|---|---|
/external/p/:processId | GET | Portal view |
/external/p/:processId/approvals/:id | GET | Approval details |
/external/p/:processId/approvals/:id | POST | Submit response |
/external/p/:processId/artifacts/:key | GET | View artifact |
Best Practices
1. Clear Participant Roles
Define specific responsibilities:
humans: {
customer_it_admin: {
requiredApprovals: ['sso_config', 'scim_config'], // Technical approvals
},
customer_ciso: {
requiredApprovals: ['security_review'], // Security approvals
},
customer_hr_manager: {
// No approvals, just informed
notifications: ['user_provisioning_complete']
}
}
2. Appropriate Timeouts
Set realistic deadlines:
// Technical review
await client.processes.requestApproval({
expiresIn: '48h',
reminderAt: ['24h']
})
// Security review (may need longer)
await client.processes.requestApproval({
expiresIn: '5d',
reminderAt: ['24h', '72h', '96h']
})
3. Provide Context
Include all information needed for decisions:
await client.processes.requestApproval({
artifacts: ['config_summary', 'test_results', 'security_scan'],
context: {
summary: 'Brief description',
impact: 'What this affects',
risks: 'Any considerations',
recommendation: 'Our recommendation'
}
})
4. Handle Escalation
Plan for non-responsive participants:
externalParticipants: [
{
participantId: 'customer_it_admin',
email: 'primary@customer.com',
escalateTo: {
email: 'backup@customer.com',
after: '72h'
}
}
]
Next: Learn about Audit Logs for tracking all process activities.