Skip to content

api.waitForEvent()

api.waitForEvent() pauses a workflow branch and returns a resume URL. When that URL is called (by a human or another system), the workflow continues from the specified next step with whatever data is POSTed to the URL.

const { token, resumeUrl } = await api.waitForEvent(options);
OptionTypeDefaultDescription
actionstringrequiredWorkflow method to call when resumed
payloadanyData passed to the next step (merged with any data POSTed to the resume URL)
timeoutnumber | string86400Seconds until the token expires. Accepts numbers (seconds) or strings like "7 days", "2 hours". Max: 30 days
redirect_urlstringnullIf set, the resume URL redirects a browser to this URL after processing instead of showing the default confirmation page

Returns { token: string, resumeUrl: string }.

class Workflow {
async start(data, headers, api) {
// Pause this branch and get a resume URL
const { resumeUrl } = await api.waitForEvent({
action: 'onApproved',
payload: { orderId: data.id },
timeout: 86400, // 24 hours
});
// Send the URL to someone who needs to act
const { token } = await api.getOAuthToken('my-slack');
await fetch('https://slack.com/api/chat.postMessage', {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` },
body: JSON.stringify({
channel: '#approvals',
text: `Order ${data.id} needs approval. <${resumeUrl}|Approve>`,
}),
});
// start() returns here — the run stays open, waiting for the resume URL to be called
}
async onApproved(data, headers, api) {
// data contains the payload passed to waitForEvent, merged with any body POSTed to resumeUrl
api.log('Order approved:', data.orderId);
// Continue processing...
}
}

Call the resume URL with a POST request. The JSON body is merged into the data argument of the next step alongside the payload you set when calling waitForEvent:

Terminal window
curl -X POST "https://hooks.jsworkflows.com/resume/{token}" \
-H "Content-Type: application/json" \
-d '{ "approvedBy": "jane@example.com" }'

A GET request to the resume URL also works — it triggers the same step with no additional data, and is useful for simple click-to-approve links in emails or Slack messages.

Set redirect_url to send the browser to a custom page after resuming instead of the default confirmation screen:

const { resumeUrl } = await api.waitForEvent({
action: 'onApproved',
payload: { orderId: data.id },
redirect_url: 'https://mystore.com/approved',
});

If the resume URL is not called before timeout seconds have elapsed, the token expires. The run stays open until the RunTracker’s next housekeeping cycle detects the expired token and marks the run as failed.

The timeout option accepts human-readable duration strings in addition to raw seconds:

StringSeconds
"30 sec" / "30 seconds"30
"5 min" / "5 minutes"300
"2 hr" / "2 hours"7200
"1 day" / "7 days"86400 / 604800
"1 week" / "2 weeks"604800 / 1209600