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.
Signature
Section titled “Signature”const { token, resumeUrl } = await api.waitForEvent(options);| Option | Type | Default | Description |
|---|---|---|---|
action | string | required | Workflow method to call when resumed |
payload | any | — | Data passed to the next step (merged with any data POSTed to the resume URL) |
timeout | number | string | 86400 | Seconds until the token expires. Accepts numbers (seconds) or strings like "7 days", "2 hours". Max: 30 days |
redirect_url | string | null | If set, the resume URL redirects a browser to this URL after processing instead of showing the default confirmation page |
Returns { token: string, resumeUrl: string }.
Example — wait for approval
Section titled “Example — wait for approval”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... }}Resuming the workflow
Section titled “Resuming the workflow”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:
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.
Browser redirect
Section titled “Browser redirect”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',});Timeout behaviour
Section titled “Timeout behaviour”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.
Duration strings
Section titled “Duration strings”The timeout option accepts human-readable duration strings in addition to raw seconds:
| String | Seconds |
|---|---|
"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 |