Guide
Actions - act when an event occurs
Firepipe Actions run steps when a file is uploaded, deleted, renamed or downloaded over SFTP - call a signed webhook, email your team, or move, copy and rename the file in your own bucket. How triggers, filters, retries and signatures work.
Files landing in a bucket usually mean something has to happen next: a system needs telling, a person needs emailing, or the file needs to move out of the inbox. Actions does that from inside Firepipe - no Lambda, no cloud-function plumbing, no polling. You build a rule visually, and Firepipe runs it every time a matching file arrives.
How a rule is shaped
A rule is one straight line:
Trigger → Filter (optional) → Step → Step → …
- Trigger - which SFTP events start the rule: upload, delete, rename, download. An upload fires when the client finishes writing and the object is safely in your bucket, so a step never sees a half-written file (a classic failure of poll-based pickup).
- Filter - narrow to files matching patterns, specific SFTP users, or a size range.
- Steps run in order. Each can be set to stop on failure, so a failed webhook can halt the move that was meant to follow it.
Open the designer from the ⚡ chip on a bucket in the Network Map (or the Actions tab in the bucket’s panel). Drag a Trigger from the palette to start a rule, drag steps after it, and connect them port-to-port. Every rule is scoped to one connection. To branch, duplicate the rule.
Steps
| Step | What it does | Where it runs |
|---|---|---|
| Webhook | POST a signed JSON payload to your HTTPS endpoint | Firepipe control plane |
| Email a verified workspace member | Firepipe control plane | |
| Notify | Post to the console notification bell | Firepipe control plane |
| Move | Move the file to another key in the same bucket | The gateway serving your connection |
| Copy | Copy the file to another key (server-side, no download) | The gateway |
| Rename | Rename the file in place | The gateway |
Move, copy and rename run on the gateway because that’s the only component holding your bucket credentials - so they work for AssumeRole connections too. They’re upload-only steps: a rule that contains one must trigger on upload alone.
Filters and patterns
Patterns follow one simple rule: no slash → match the file name anywhere; a slash → match the full key.
| Pattern | Matches |
|---|---|
*.csv | any .csv at any depth |
report-*.{csv,xlsx} | report-2026.csv, sub/dir/report-q3.xlsx |
inbox/**/*.csv | .csv files anywhere under inbox/ |
inbox/*.csv | .csv files directly in inbox/ only |
Keys are matched against the full object key in your bucket, including a user’s home folder prefix. For a rename trigger, the pattern is tested against the new key. The Filter panel has a live tester - paste a key and see whether the rule would fire.
Placeholders
Destinations, webhook URLs, subjects and messages can use {{placeholders}}:
| Placeholder | Value (for inbox/2026/report.final.csv) |
|---|---|
{{path}} | inbox/2026/report.final.csv |
{{dir}} | inbox/2026 |
{{name}} | report.final.csv |
{{stem}} | report.final |
{{ext}} | csv |
{{size}} | bytes, e.g. 48213 |
{{event}} | upload / delete / rename / download |
{{user}} · {{username}} | SFTP user, short / full login |
{{connection}} · {{bucket}} | the connection’s name / bucket |
{{date}} · {{time}} | 2026-08-26 · 102030 (UTC) |
{{src}} | the previous key (rename events) |
{{rule}} | the rule’s name |
A destination is a full key - processed/{{date}}/{{name}} moves today’s arrivals into a dated
folder. Destinations can’t start with / or contain .., and that’s checked again after the
placeholders are filled in.
Webhook payload and signature
Every webhook request is a JSON POST:
{
"id": "18342",
"attempt": 1,
"event": "upload",
"event_id": 34291,
"occurred_at": "2026-08-26T10:20:30.412Z",
"rule": { "id": "6b2c…", "name": "CSV arrivals" },
"connection": { "id": "0f9a…", "name": "Acme inbound", "bucket": "acme-inbound" },
"file": { "path": "inbox/2026/report.csv", "dir": "inbox/2026", "name": "report.csv", "ext": "csv", "size": 48213 },
"user": { "username": "acme/alice", "ip": "203.0.113.5" }
}
Headers:
X-Firepipe-Event-Id- the delivery id (idabove); the same value on every retry.X-Firepipe-Timestamp- unix seconds when the request was signed.X-Firepipe-Signature-sha256=+ HMAC-SHA256 of"<timestamp>.<raw body>"using the rule’s signing secret (shown once when the webhook step is saved).X-Firepipe-Attempt- 1 for the first try, then 2, 3…
Verify in Node:
import { createHmac, timingSafeEqual } from 'node:crypto';
function verify(req, rawBody, secret) {
const ts = req.headers['x-firepipe-timestamp'];
const sig = req.headers['x-firepipe-signature'] ?? '';
const expected = 'sha256=' + createHmac('sha256', secret).update(`${ts}.${rawBody}`).digest('hex');
const fresh = Math.abs(Date.now() / 1000 - Number(ts)) < 300; // 5-minute replay window
return fresh && sig.length === expected.length && timingSafeEqual(Buffer.from(sig), Buffer.from(expected));
}
Use X-Firepipe-Event-Id to de-duplicate: a delivery may be retried after a network failure even
if you already processed it.
Endpoints must be HTTPS with a publicly trusted certificate. Firepipe never follows redirects and refuses hosts that resolve to private or link-local addresses, at save time and at request time.
Retries, and what “delivered” means
- A step is queued the moment the file event is recorded. Delivery is at-least-once from that point: a crash or redeploy mid-delivery re-runs the step rather than losing it.
- Transient failures retry: HTTP
5xx,429,408, and network errors. The wait grows - 30 s, 1 min, 2 min … up to an hour - with jitter, for up to 8 attempts. - Permanent failures (any other
4xx, a redirect, a bad destination) fail immediately. - Move/copy/rename steps are idempotent: if a retry finds the source gone and the destination present, the step counts as done.
- A rule that fails 5 times in a row is paused and you’re told in the console bell. Fix the endpoint, then Resume the rule. Any run can be replayed from the runs log.
The runs log (the Runs button in the designer) shows every attempt with its outcome: succeeded, retrying, failed, or skipped (an earlier step stopped the chain).
Limits and safety
- Rules per workspace follow your plan (Free 1, Starter 3, Growth unlimited).
- Email goes only to verified workspace members - an action can’t be turned into a mail relay. 100 action emails per workspace per hour.
- Webhooks: 120 deliveries per workspace per minute; response bodies over 64 KB are truncated in the log.
- Moves and copies made by a rule are recorded in your Logs but never re-trigger rules, so a rule can’t loop on its own output.
- Actions fire on SFTP activity through Firepipe. Files written straight to the bucket by other tools don’t trigger rules today.
- In the rare case of sustained overload the gateway sheds audit events rather than slowing a transfer; a shed event also skips its actions. This is the same path that meters transfer, and it’s logged when it happens.
Try it on your own bucket
Connect a bucket you already own, Amazon S3, Azure Blob, Google Cloud Storage, or an S3-compatible store, and hand out a clean SFTP endpoint in minutes. Your files stay in your cloud.
Start free