Trigger types
| Type | Description |
|---|---|
| Manual | Run the workflow on demand by clicking Run in the toolbar |
| Webhook | Run when an external HTTP request hits the workflow’s webhook URL. Supports Spojit’s own scheme plus Shopify, GitHub, Slack, and custom HMAC verification |
| Schedule | Run on a cron schedule (e.g., every hour, daily at 9 AM) |
| Run when a new email arrives in a connected mailbox (Gmail or Outlook) | |
| Mailhook | Run when an email is sent to the workflow’s own generated address (no mailbox required). See the Mailhook Trigger page |
Manual
No additional configuration needed. Click Run in the designer toolbar to execute the workflow. The request body you pass (if any) is available as the trigger output for downstream nodes.Webhook
A webhook trigger fires when an external HTTP service POSTs to its unique URL. Spojit verifies the request’s HMAC signature against a webhook signing connection that you create once per upstream app and reuse across as many workflows as you like.How signing connections work
Each webhook trigger references aConnection that owns:
- A scheme: one of
Spojit,Shopify,GitHub,Slack, orCustom. The scheme determines which header carries the signature, what gets signed, and how it’s encoded. - One or two signing secrets. Two enables zero-downtime rotation; both verify simultaneously during the rotation window.
Setup
- Select the trigger node, set Trigger Type to Webhook.
- Click + next to the Signing connection picker.
- Pick a connector tile:
- Spojit: we generate the secret. Pick this when you control both sides of the integration (your own backend, scripts, internal tools).
- Shopify / GitHub / Slack: paste the signing secret from your provider’s app settings.
- Custom: for any provider we don’t have a preset for; you configure header, encoding, algorithm, and payload shape.
- Name the connection (e.g. “Shopify production”), provide the secret if applicable, and Create.
- The connection is auto-selected. Copy the Webhook URL and paste it into your provider’s webhook configuration.
Choosing a scheme
| Scheme | Header | Signed payload | Encoding | Pick when |
|---|---|---|---|---|
| Spojit | X-Spojit-Signature: t=<ts>,v1=<hex> | <unix-ts>.<body> | hex | Your own backend / scripts / tools |
| Shopify | X-Shopify-Hmac-Sha256 | raw body | base64 | Inbound from a Shopify app |
| GitHub | X-Hub-Signature-256: sha256=<hex> | raw body | hex | Inbound from a GitHub App or repo webhook |
| Slack | X-Slack-Signature: v0=<hex> (+ X-Slack-Request-Timestamp) | v0:<ts>:<body> | hex | Inbound from a Slack app’s Events API |
| Custom | configurable | configurable | configurable | Anything we don’t have a preset for |
Provider presets
Spojit
We generate awhsec_… secret on connection create and show it once. Sign every request like this:
- Compute Unix timestamp in seconds
- HMAC-SHA256 of
<timestamp>.<raw-body>using your secret - Hex-encode the result
- Send as header:
X-Spojit-Signature: t=<timestamp>,v1=<hex> - Optional:
X-Spojit-Event-Id: <unique-id>for deduplication.
Shopify
In your Shopify admin: Settings → Notifications → Webhooks. Each webhook subscription has a signing secret you can reveal; paste it when creating the connection. Spojit verifiesX-Shopify-Hmac-Sha256 (base64-encoded HMAC-SHA256 of the raw body). Deduplication uses Shopify’s X-Shopify-Webhook-Id header.
Provider docs: Shopify webhooks configuration.
GitHub
In GitHub: when creating the webhook on a repository or GitHub App, set a Secret value. Paste the same value when creating the Spojit connection. Spojit verifiesX-Hub-Signature-256: sha256=<hex>. Deduplication uses GitHub’s X-GitHub-Delivery header.
Provider docs: Validating webhook deliveries.
Slack
In your Slack app: Basic Information → App Credentials → Signing Secret. Paste it when creating the Spojit connection. Spojit verifiesX-Slack-Signature: v0=<hex> over v0:<ts>:<body>, with the timestamp in X-Slack-Request-Timestamp (5-minute skew). Deduplication uses Slack’s X-Slack-Event-Id header.
URL verification: Slack sends a one-time url_verification event when you save the webhook URL. Spojit handles this automatically: it verifies the HMAC, then echoes the challenge field as text/plain. No workflow run is dispatched for verification events.
Provider docs: Verifying requests from Slack.
Custom
For providers without a preset, configure each axis explicitly:| Field | Description |
|---|---|
| Signature header name | The HTTP header carrying the HMAC (e.g. X-Vendor-Signature). |
| Algorithm | SHA-256 (default), SHA-1 (weak, legacy only), SHA-512. |
| Encoding | hex or base64. |
| Value prefix | Optional literal string stripped before comparison (e.g. sha256=). |
| Signed payload | Raw body (sign body verbatim) or Timestamp.body (Stripe-style, requires a timestamp header). |
| Timestamp header / skew | Required when payload includes a timestamp. |
| Event ID header | Optional; used for deduplication. |
Example: Postman
To test your webhook from Postman: Request:- Method:
POST - URL: your webhook URL (from the trigger properties panel)
- Headers:
Content-Type: application/jsonX-Spojit-Signature: generated by the pre-request script belowX-Spojit-Event-Id: any unique string (optional; used for deduplication)
- Body (raw JSON):
whsec_YOUR_SECRET_HERE with your actual signing secret.
Example: Node.js
Example: Python
Response codes
| Code | Meaning |
|---|---|
202 | Accepted: workflow run dispatched. Response includes executionId and status. |
401 | Signature missing, invalid, or timestamp outside the 5-minute tolerance window. |
404 | Trigger not found or inactive. |
409 | Duplicate event: a request with the same event-id header was already processed. Response includes the original executionId. |
402 | Insufficient credits. |
403 | Not authorized to run this workflow. |
500 | Internal error. |
Deduplication
Deduplication is opt-in via an event-id header. When the header is present, a second request with the same id on the same webhook returns409 with the original executionId instead of running the workflow again. When it’s absent, every request fires a fresh execution.
The header depends on the connection type:
| Connection type | Event-id header |
|---|---|
| Spojit Webhook | X-Spojit-Event-Id (optional; set per logical event if you want retries deduped) |
| Shopify Webhook | X-Shopify-Webhook-Id (Shopify sends automatically) |
| GitHub Webhook | X-GitHub-Delivery (GitHub sends automatically) |
| Slack Webhook | event_id field in the request body (Slack sends automatically) |
| Custom Webhook | The header name you configured under Event ID header when creating the connection |
Secret rotation
Each connection can hold up to 2 active signing secrets at a time, enabling zero-downtime rotation. Because rotation lives on the connection, all triggers using that connection rotate atomically; there’s never a window where some workflows accept the old secret and others don’t. Open the connection’s detail page (Connections → My Connections → Configure on the row), then:- Click Rotate / add secret to create a second secret.
- Spojit scheme: copy the newly generated secret (shown once). Other schemes: rotate the secret upstream (in Shopify / GitHub / Slack admin, etc.), then paste the new value here.
- Both secrets verify simultaneously. Check the Last used timestamp on each; once the new secret shows recent activity, you’ve fully cut over.
- Delete the old secret.
Webhook payload
The full HTTP request body is passed as the trigger output to downstream nodes. If the body is valid JSON, it’s parsed automatically. Otherwise, it’s available as a raw string under{ raw: "..." }.
Polling execution status
When your webhook returns 202 Accepted (either async mode, or sync mode that hit its timeout), you’ll get back anexecutionId. You can poll the status endpoint to find out where the run is and retrieve the output once it’s done.
Endpoint:
{timestamp}.{executionId}.
| Field | Description |
|---|---|
status | PENDING, RUNNING, WAITING_APPROVAL, COMPLETED, FAILED, or CANCELLED |
currentStep | The step currently executing (or waiting, e.g. for approval). null when the run has finished. |
stepsCompleted | Count of steps that have reached COMPLETED. Grows as the run progresses. |
totalSteps | Total work-producing steps in the workflow. Only populated for linear workflows. Returns null if the graph contains any Condition, Loop, or Parallel node (actual path length is dynamic). |
output | The workflow’s output, populated once status === 'COMPLETED'. When the workflow ends with a Response node, this mirrors its { statusCode, headers, body } shape. |
error | Error message if status === 'FAILED', otherwise null. |
| Code | Meaning |
|---|---|
200 | Status retrieved |
401 | Signature missing, invalid, expired (>5 min), or the originating trigger has no signing secrets |
404 | Execution not found |
Example: Node.js polling
Example: Python polling
Example: Postman
Same pre-request script as the webhook call, but with the payload changed to sign{timestamp}.{executionId}:
Recommended polling cadence
- Start with 1–2 second intervals for short-running workflows
- Back off to 5–10 seconds for workflows that routinely take minutes
- Always stop polling once
statusisCOMPLETED,FAILED, orCANCELLED; these are terminal
Schedule
Run a workflow automatically on a cron schedule. Each firing produces an independent workflow execution, identical in every way to a manually triggered run.Setup
- Select the trigger node in the designer
- Set Trigger Type to Schedule
- Click Add Schedule
- Edit the Cron expression (5-field Unix cron, e.g.,
0 9 * * 1-5for 9 AM weekdays) - Pick a Timezone (IANA, e.g.
Australia/Sydney,America/New_York) - Leave Active on to have it fire; toggle off to pause
- Click Save workflow; the schedule begins firing on the next matching time
Multiple schedules
A single trigger node can hold any number of schedules. Use this to model real-world timing needs such as:- Business hours vs. weekends: one schedule for
0 9 * * 1-5(weekdays 9 AM) and another for0 12 * * 0,6(weekends noon) - Peaks and off-peaks: run every 15 minutes during business hours, every hour overnight
- Multi-region timing: one schedule in
America/New_York, another inEurope/London, both hitting the same workflow
Cron format
Schedules use standard 5-field Unix cron:| Expression | Meaning |
|---|---|
0 * * * * | Every hour on the hour |
*/15 * * * * | Every 15 minutes |
0 9 * * * | Every day at 9 AM |
0 9 * * 1-5 | 9 AM on weekdays |
0 0 1 * * | Midnight on the 1st of every month |
0 9 * * 1 | 9 AM every Monday |
Timezones
Every schedule has an IANA timezone (e.g.Australia/Sydney, Europe/London, UTC). The cron expression is evaluated in that timezone, which means daylight savings transitions are handled correctly; a 0 9 * * * schedule in America/New_York fires at 9 AM local time year-round, not at a fixed UTC offset.
Pausing a schedule
Toggle the Active switch off and save the workflow. The schedule is retained in the workflow’s configuration (so you can re-enable it later) but won’t fire while paused. This is reversible without losing the cron/timezone configuration.Tips
- The Next fires preview shows the saved schedule, not your draft edits, so it’s a trustworthy readout of what’s actually going to run
- You can combine a Schedule trigger with a Manual or Webhook trigger on the same workflow. Each is an independent entrypoint that converges on the same downstream logic.
- Keep the cron on conservative intervals during development (e.g. every 10 min) to validate behavior before switching to production cadence
How it works
You connect a mailbox to Spojit via OAuth (the OAuth grant is read-only by default; no password sharing). Spojit polls that mailbox on a schedule you choose and fires a workflow execution for every new message that matches your filters. The mail itself never travels through any third party; Spojit reads it directly from your provider (Google or Microsoft) using the OAuth token you granted.Recommended pattern: dedicated mailbox
Instead of connecting your everyday inbox, create a dedicated mailbox in your workspace just for the workflow, for exampleorders-automation@acme.com. Then set up a forwarding rule (or share the address with senders) so only the relevant emails land there. Benefits:
- Clear scope: Spojit only ever sees the dedicated mailbox, not your personal inbox
- Easy to revoke: disconnect the mailbox in Spojit or delete the mailbox in your workspace; either kills access
- Easy to audit: IT can see exactly what’s flowing through the dedicated address
Setup
- Connect the mailbox in the Connections page:
- Click Add connection → pick Gmail (trigger) or Outlook (trigger)
- Choose a permission level:
- Read only: Spojit can only read messages
- Read + modify: Spojit can also mark messages as read or move them after processing (needed for the optional “After processing” actions below)
- Sign in with the account that owns the mailbox
- The connection appears in your list with the granted scopes visible
- Add the trigger in the workflow designer:
- Drop a Trigger node, set Trigger Type to Email
- Click Add mailbox
- Pick the connection from the dropdown
- Pick the folder/label to watch (e.g.,
INBOX, or a custom label likeSpojit/Orders) - Set the poll interval (1–60 minutes; default 2)
- Optional: filter by sender domain or subject regex
- Optional: pick what to do with the message after Spojit processes it
- Click Save workflow; Spojit starts polling on the next cycle
Filters
Two optional filters narrow what triggers a run:- From allowlist: comma-separated patterns.
@acme.commatches any sender at acme.com;orders@vendor.commatches the exact address. Multiple patterns are OR’d. - Subject regex: a JavaScript-flavor regular expression. The message fires only if the subject matches.
After processing
By default Spojit doesn’t touch the message; it stays in your folder, in whatever read state it was. If you want, you can ask Spojit to:- Mark as read: useful for visual confirmation that Spojit picked it up
- Move to label / folder: pick a destination; in Gmail the label is added (other labels stay), in Outlook the message moves out of the source folder
Multiple mailboxes per workflow
A single workflow can watch multiple mailboxes, useful for things like “watch our US orders mailbox AND our EU orders mailbox, both run the same processing logic.” Add as many as you need; each fires the workflow independently.Multiple workflows watching the same mailbox
Different workflows can watch the same mailbox + folder. Every matching message fires every matching workflow, independently and in parallel. Common pattern: one workflow processes the order into your ERP, another notifies sales on Slack, and both fire on each incoming email. A few important behavior notes for this pattern:- No “first one wins”: each workflow gets its own copy of the email, runs its own logic
After processingactions don’t hide messages from siblings: even if Workflow A moves the message to aProcessedfolder, Workflow B still sees and processes it within the same poll cycle. You won’t miss a workflow because of another workflow’s cleanup action.- Conflicting after-processing actions apply in order: if A says “mark read” and B says “move to folder X”, both happen. In Gmail, labels accumulate; in Outlook, the move wins.
What Spojit can and can’t see
- Can see: messages in the folder you select. Spojit’s code is committed to only querying that folder, even though the OAuth scope technically grants whole-mailbox access (this is how Google/Microsoft OAuth scopes work; folder-level scoping isn’t an option from the provider).
- Can’t do (read-only connections): mark messages as read, move messages, delete messages
- Can do with Read + modify (only if you picked it at connection setup): mark as read, move/label, but never delete
- Doesn’t store: full message bodies. Bodies and attachments are passed into the workflow execution and retained per the workflow execution’s normal retention policy. They are not stored in any separate Spojit-owned mailbox.
Disconnecting
In the Connections page, click Remove on the email connection. Spojit deletes the OAuth token and stops polling immediately. To revoke at the provider side as well (defense in depth):- Google: myaccount.google.com/permissions → find Spojit → Remove access
- Microsoft: myaccount.microsoft.com/consent → find Spojit → Remove
Tips
- Start with a dedicated mailbox: much easier story for IT and for limiting blast radius
- Use Read only by default; only upgrade to Read + modify if you actually want Spojit to mark or move messages
- The poll interval doesn’t need to be aggressive; 2–5 minutes is fine for almost every order-processing use case; 1-minute polls aren’t dramatically faster end-to-end given queue + provider latency
- Pair a dedicated mailbox with a forwarding rule from your main inbox to filter just the messages you want Spojit to act on
- For testing, send yourself an email matching your filters and watch the Recent activity panel to confirm it landed
Mailhook
A mailhook gives the workflow its own unique email address (e.g.mh-x7k2m9qf4a3vbn8c@mailhook.spojit.com). Any message sent to that address starts a run, with no mailbox connection or OAuth involved: a webhook, but for email. Delivery is push rather than polling, so runs start seconds after the message arrives.
Use a mailhook when you control where the mail gets sent (vendor notification settings, forwarding rules, system-generated mail). Use the Email trigger when the mail already lands in a mailbox you own.
Full documentation, including address rotation, filters, and the input payload shape, is on the Mailhook Trigger page.
Output
The trigger node produces an output that downstream nodes can reference:- Manual: The input data passed when clicking Run (if any)
- Webhook: The parsed HTTP request body
- Schedule:
{ scheduledAt }, the ISO-8601 timestamp of the firing that started the run - Email:
{ from, to, cc, subject, textBody, htmlBody, headers, receivedAt, conversationId, attachments[] }. Each attachment is a reference ({ provider, providerMessageId, attachmentId, filename, mimeType, size }); the bytes are fetched on demand by downstream nodes that need them. - Mailhook:
{ from, to, cc, replyTo, subject, text, html, truncated, receivedAt, emailId, messageId, attachments[] }. Each attachment is a reference ({ id, filename, contentType }); the bytes are fetched on demand by downstream nodes that need them. See Mailhook Trigger for the full shape.
Tips
- Start with Manual triggers during development, then switch to Webhook, Schedule, Email, or Mailhook when you’re ready for production
- A workflow can have multiple triggers (e.g., Manual + Webhook, or Schedule + Email); each is an independent entrypoint
- Use the Active toggle to temporarily pause any trigger without deleting it or losing the configuration