File Upload Webhook: Trigger Automation After Every Upload
Uploading a file is rarely the end of the workflow. Usually it is the start: notify a Slack channel, update a database row, kick off a resize job, or push the public URL into the next pipeline step.
With FilePost you can now attach one webhook URL to your account. Every time an API upload finishes, FilePost sends a signed file.uploaded event to that URL — automatically retried until your receiver answers. No polling, no scheduled checks, no "did it work?" scripts.
What the event looks like
The payload carries everything your workflow needs to react:
{
"event": "file.uploaded",
"file_id": "8f3kX9aQ2v",
"url": "https://cdn.filepost.dev/8f3kX9aQ2v/report.pdf",
"size": 48291,
"content_type": "application/pdf",
"original_name": "report.pdf",
"filename_mode": "download",
"upload_source": "api",
"expires_at": null,
"uploaded_at": "2026-08-07T12:34:56+00:00"
}
| Field | What it tells you |
|---|---|
file_id / url | The stable identifier and public CDN URL you can store or pass on. |
size / content_type / original_name | Metadata for routing, validation, or database columns. |
upload_source | Which client made the upload: api, n8n, zapier, make, or pipedream. |
expires_at | When the file is set to auto-delete, or null for permanent files. |
Set it up in three steps
1. Point FilePost at your receiver. The URL must be https:// and is stored per account:
curl -X PUT https://filepost.dev/v1/webhook \
-H "X-API-Key: $FILEPOST_API_KEY" \
-H "Content-Type: application/json" \
-d '{"webhook_url":"https://your-app.example.com/hooks/filepost"}'
2. Send a test event. This gives you instant feedback instead of waiting for the next upload:
curl -X POST https://filepost.dev/v1/webhook/test \
-H "X-API-Key: $FILEPOST_API_KEY"
# {"event":"ping","ok":true,"status_code":200,"attempts":1,"error":null}
You can do the same from the dashboard: Webhooks → Save → Test, and it reports your receiver's actual HTTP status.
3. Upload as usual. Every successful upload to /v1/upload or /v1/upload/base64 fires the event. Remove the URL with DELETE /v1/webhook when you want it to stop.
Verify the signature so you know it's really FilePost
Each request includes an X-FilePost-Signature header:
X-FilePost-Signature: sha256=<hex-digest>
The digest is an HMAC-SHA256 of the raw request body, keyed with the API key that performed the upload. In Python:
import hashlib
import hmac
def is_valid_filepost_signature(body: bytes, signature: str, api_key: str) -> bool:
expected = hmac.new(
api_key.encode(),
body,
hashlib.sha256,
).hexdigest()
return hmac.compare_digest(f"sha256={expected}", signature)
Verify the signature before trusting the payload — especially if your receiver triggers side effects like writing to a database or sending messages.
Retries are built in
Delivery runs after the upload response is sent, so a slow receiver never slows down your uploads. FilePost retries up to four times with backoff, and stops as soon as your endpoint answers. A 2xx or 3xx response is success; 5xx errors and network timeouts are retried; permanent errors like a 404 stop the retries so you can fix the URL.
Because retries happen, make your receiver idempotent: use file_id as the dedupe key so one event can never create two database rows or two Slack messages.
Real workflow: notify a Slack channel when a client uploads
In n8n, add a Webhook trigger node with POST and point it at your FilePost webhook URL. The JSON body arrives with all the fields above, so the next node can read body.url, body.original_name, and body.size. Send those to a Slack node and you have a "new file uploaded" notification with a working link — no polling.
In Zapier, use the Webhooks by Zapier → Catch Hook trigger, paste the same URL, and map the returned fields into the next step.
For a custom backend, a minimal FastAPI receiver looks like this:
import os
import hashlib
import hmac
from fastapi import FastAPI, Header, Request, HTTPException
app = FastAPI()
@app.post("/hooks/filepost")
async def filepost_hook(
request: Request,
x_filepost_signature: str = Header(default=""),
):
body = await request.body()
expected = hmac.new(
os.environ["FILEPOST_API_KEY"].encode(),
body,
hashlib.sha256,
).hexdigest()
if not hmac.compare_digest(f"sha256={expected}", x_filepost_signature):
raise HTTPException(status_code=401, detail="Bad signature")
event = await request.json()
if event["event"] == "file.uploaded":
# e.g. write event["file_id"], event["url"], event["size"] to your DB
pass
return {"received": True}
Included on every plan
Webhooks work on the free plan, so you can build the pattern before you pay anything. The free plan includes 50 uploads per month after email verification. When you outgrow it, the Lite plan at $4/month raises you to 300 uploads, 100 MB per file, and 10 GB of storage — without changing how your webhook receiver works.
Get notified when your next upload finishes
Set the webhook in the dashboard, send a test, and your pipeline is live.
Get Your Free API Key