Wait Steps
Pause workflow execution for timed delays
Wait Steps
Wait steps pause workflow execution for a specified duration. They're useful for rate limiting, scheduling delays, and allowing external processes to complete.
Configuration
{
"id": "wait-before-retry",
"type": "wait",
"name": "Wait Before Retry",
"config": {
"duration": 5000
}
}| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Unique step identifier |
type | string | Yes | Must be "wait" |
name | string | Yes | Human-readable name |
config.duration | number | Yes | Wait time in milliseconds |
Duration
The duration field specifies how long to pause in milliseconds:
{
"config": {
"duration": 30000
}
}Common Durations
| Duration | Milliseconds | Use Case |
|---|---|---|
| 1 second | 1000 | Quick pause |
| 5 seconds | 5000 | Brief delay |
| 30 seconds | 30000 | Rate limiting |
| 1 minute | 60000 | Processing time |
| 5 minutes | 300000 | External sync |
| 1 hour | 3600000 | Scheduled delay |
Output
Wait steps return information about the wait:
{
"waited": 5000
}| Field | Description |
|---|---|
waited | The actual duration waited (in ms) |
Common Patterns
Rate Limiting
Add delays between API calls to avoid rate limits:
{
"steps": [
{
"id": "first-api-call",
"type": "action",
"action": "hubspot.getContact",
"config": { "contactId": "{{input.contactId}}" }
},
{
"id": "rate-limit-delay",
"type": "wait",
"name": "Rate Limit Delay",
"config": {
"duration": 1000
}
},
{
"id": "second-api-call",
"type": "action",
"action": "hubspot.updateContact",
"config": {
"contactId": "{{input.contactId}}",
"properties": { ... }
}
}
]
}Retry with Delay
Wait before retrying a failed operation:
{
"steps": [
{
"id": "attempt-sync",
"type": "action",
"action": "salesforce.updateAccount",
"config": { ... },
"errorHandling": {
"strategy": "continue",
"fallback": { "success": false }
}
},
{
"id": "check-success",
"type": "condition",
"config": {
"conditions": {
"left": "{{steps.attempt-sync.output.success}}",
"operator": "eq",
"right": "false"
},
"then": ["wait-and-retry"],
"else": ["continue-flow"]
}
},
{
"id": "wait-and-retry",
"type": "wait",
"name": "Wait Before Retry",
"config": {
"duration": 5000
}
},
{
"id": "retry-sync",
"type": "action",
"action": "salesforce.updateAccount",
"config": { ... }
}
]
}Processing Delay
Wait for external system to process:
{
"steps": [
{
"id": "submit-document",
"type": "action",
"action": "pandadoc.sendDocument",
"config": {
"documentId": "{{input.documentId}}"
}
},
{
"id": "wait-for-processing",
"type": "wait",
"name": "Wait for Document Processing",
"config": {
"duration": 10000
}
},
{
"id": "check-status",
"type": "action",
"action": "pandadoc.getDocumentStatus",
"config": {
"documentId": "{{input.documentId}}"
}
}
]
}Scheduled Notification Delay
Delay a notification:
{
"steps": [
{
"id": "create-invoice",
"type": "action",
"action": "stripe.createInvoice",
"config": { ... }
},
{
"id": "wait-before-reminder",
"type": "wait",
"name": "Wait 24 Hours",
"config": {
"duration": 86400000
}
},
{
"id": "send-reminder",
"type": "action",
"action": "slack.sendMessage",
"config": {
"channel": "#finance",
"text": "Invoice {{steps.create-invoice.output.id}} is still unpaid"
}
}
]
}Polling Pattern
Poll for status with delays:
{
"steps": [
{
"id": "start-export",
"type": "action",
"action": "netsuite.createExport",
"config": { "type": "invoices" }
},
{
"id": "poll-status",
"type": "loop",
"config": {
"collection": [1, 2, 3, 4, 5],
"itemVariable": "attempt",
"steps": ["check-export", "wait-if-pending"]
}
},
{
"id": "check-export",
"type": "action",
"action": "netsuite.getExportStatus",
"config": {
"exportId": "{{steps.start-export.output.id}}"
}
},
{
"id": "wait-if-pending",
"type": "condition",
"config": {
"conditions": {
"left": "{{steps.check-export.output.status}}",
"operator": "eq",
"right": "pending"
},
"then": ["wait-poll"],
"else": []
}
},
{
"id": "wait-poll",
"type": "wait",
"name": "Poll Delay",
"config": {
"duration": 5000
}
}
]
}Dynamic Duration
Use template expressions for dynamic wait times:
{
"id": "dynamic-wait",
"type": "wait",
"name": "Dynamic Delay",
"config": {
"duration": "{{input.delayMs}}"
}
}Or calculate based on previous step output:
{
"steps": [
{
"id": "get-retry-delay",
"type": "transform",
"config": {
"action": "map",
"sourceData": "{{input}}",
"mappingRules": [
{
"source": "retryCount",
"target": "delayMs",
"customTransform": "Multiply by 1000 for exponential backoff"
}
]
}
},
{
"id": "backoff-wait",
"type": "wait",
"name": "Exponential Backoff",
"config": {
"duration": "{{steps.get-retry-delay.output.delayMs}}"
}
}
]
}Best Practices
Reasonable Timeouts
Keep wait durations reasonable for your use case:
- API rate limiting: 100-1000ms
- Processing delays: 5-30 seconds
- Polling intervals: 5-60 seconds
- Scheduled delays: Use schedule triggers instead for hours/days
Avoid Long Waits
For delays longer than a few minutes, consider:
- Schedule triggers - Use cron or interval triggers instead
- Subworkflows - Split workflow at natural pause points
- External scheduling - Let external systems handle timing
Idempotency
Design steps after waits to be idempotent in case of restarts:
{
"steps": [
{
"id": "wait-for-sync",
"type": "wait",
"config": { "duration": 60000 }
},
{
"id": "check-already-processed",
"type": "condition",
"config": {
"conditions": {
"left": "{{steps.lookup.output.processed}}",
"operator": "eq",
"right": "true"
},
"then": [],
"else": ["do-processing"]
}
}
]
}Troubleshooting
Wait Not Working
- Check duration type - Must be a number in milliseconds
- Verify template resolution - Dynamic values must resolve to numbers
- Check workflow status - Workflow must be active
Workflow Timeout
If your total wait time exceeds the workflow timeout:
- Split into subworkflows - Break at natural boundaries
- Use schedule triggers - For long delays
- Reduce polling frequency - Increase wait duration between checks
Resource Usage
Long-running waits consume resources:
- Use appropriate intervals - Don't poll too frequently
- Consider schedules - For regular intervals
- Monitor run duration - Track total workflow time