Cron-polling an FTP directory is the default pattern almost everyone reaches for first, and it quietly causes most FTP ingestion pain. The scheduler wakes on a fixed interval whether or not a file landed, so you pay for empty runs and add minutes of latency to every real one. It races the uploader, so a poll can grab a half-written file. And it needs lockfiles, "seen" tracking and clean-up logic just to avoid processing the same file twice. An event-driven webhook removes the whole category of problem: nothing fires until an upload actually completes.

How the webhook replaces polling

  1. A client connects over FTP, FTPS or SFTP and runs a STOR (upload). FTPasHTTPS receives the bytes as a stream — nothing is written to disk.
  2. When the upload completes, FTPasHTTPS fires an HTTPS POST webhook to your endpoint, signed with HMAC-SHA256.
  3. The file bytes can stream into the webhook body, or you can send a lightweight notification with metadata and fetch the file yourself.
  4. Your 200 acknowledges the event and the client sees 226 Transfer complete; a 5xx maps to 451 Action aborted so the client resends.
  5. Failed deliveries retry with exponential backoff, fall back to a dead-letter queue, and every attempt is written to the audit log.

Configuration + example event

A webhook target is a small JSON config. You give the URL and choose whether the body carries the raw file or just an event notification:

# Webhook target replaces the polling cron
{
  "protocol": "sftp",
  "auth": { "type": "ssh-key" },
  "forward": {
    "type": "webhook",
    "url": "https://app.example.com/hooks/ftp-upload",
    "delivery": "notification",
    "sign_with": "hmac-sha256"
  }
}

When a client finishes uploading claims-2026-06-20.csv, your endpoint receives a signed event the instant the transfer completes — no schedule involved:

# POST https://app.example.com/hooks/ftp-upload
Content-Type: application/json
X-FTPasHTTPS-Signature: sha256=7c2b9a04e1f6...
X-FTPasHTTPS-Event: file.uploaded

{
  "event": "file.uploaded",
  "protocol": "SFTP",
  "user": "claims-partner",
  "filename": "claims-2026-06-20.csv",
  "size_bytes": 84213,
  "received_at": "2026-06-20T09:02:11Z"
}

Send the file, not just the ping. Set delivery to stream the upload bytes straight into the webhook body and the event becomes the file itself — no second round-trip to fetch it. On Professional and above you can also run an inline transform first, so the body arrives as validated JSON instead of raw CSV.

Webhook vs. the polling cron job

ConcernCron polling an FTP inboxFTPasHTTPS webhook
TriggerFixed schedule, whether or not files arrivedThe completed upload itself
LatencyUp to a full poll interval (minutes)Near-instant on upload
Partial filesCan read a half-written fileFires only after the transfer completes
Dedup logicLockfiles + "seen" tracking you maintainOne event per upload, no bookkeeping
AuthenticityNone — you trust the directoryHMAC-SHA256 signed per request
Failure handlingRe-scan and hopeBackoff retries + dead-letter queue
Files on diskSit in the inbox until sweptStreamed — never touch disk

When to use it (and the limits)

Replace polling with a webhook whenever ingestion latency matters, when empty cron runs are wasting compute, or when partial-file reads and dedup bookkeeping have become a source of bugs. Webhooks are available on every paid tier and the Free tier supports FTP, so you can prove the event-driven flow before scaling up. SFTP (SSH key auth) and inline transforms begin on the Professional plan (€49/server/month: 10,000 transfers, 50GB); Starter (€19) adds FTPS to the Free FTP baseline.

A couple of limits to keep in mind: the webhook fires per completed upload, so it is not a mechanism for reacting to files that already exist somewhere — it reacts to new transfers through FTPasHTTPS. And delivery volume counts against your plan's monthly transfer cap (100 on Free, 1,000 on Starter, 10,000 on Professional, 50,000 on Enterprise), so size the plan to your expected upload rate.

Making the webhook reliable and verifiable

Every webhook carries an X-FTPasHTTPS-Signature header containing an HMAC-SHA256 of the body keyed with your server secret. Recompute it and compare in constant time before acting on the event — that single check is what makes a public webhook endpoint safe, because anything that fails it did not come from FTPasHTTPS. Since the file never lands on a shared volume, there is also no inbox to lock down or sweep, which removes the most common FTP-polling foot-gun outright.

Reliability comes from the retry path. If your endpoint is briefly down or returns a 5xx, the delivery is retried with exponential backoff; if it keeps failing it moves to the dead-letter queue rather than vanishing, and the uploading client is told the transfer aborted so it can resend. The audit log records every attempt with its outcome, giving you one authoritative place to answer the question polling could never answer cleanly: did this exact file get delivered, and when?

Frequently asked questions

How do I replace FTP polling with a webhook?

Point your FTP, FTPS or SFTP clients at FTPasHTTPS and configure a webhook URL instead of polling an inbox. The moment a client finishes an upload, FTPasHTTPS POSTs an HMAC-signed event to your endpoint, so ingestion is triggered by the upload itself rather than by a cron schedule.

Why is a webhook better than polling an FTP directory?

Polling adds latency equal to the cron interval, fires whether or not anything arrived, and can pick up half-written files. A webhook is event-driven: it fires only when an upload completes, with no wasted runs, no interval lag and no risk of reading a partial file.

How do I know the webhook really came from FTPasHTTPS?

Every webhook is signed with HMAC-SHA256 over the request body using your server's secret. Recompute the signature on your side and compare it before trusting the event, so spoofed or replayed requests are rejected.

What happens if my webhook endpoint is down?

Failed deliveries are retried automatically with exponential backoff and, if they keep failing, land in a dead-letter queue rather than being lost. The uploading client receives a 451 Action aborted code so it knows to resend, and every attempt is recorded in the audit log.

Can the webhook include the file contents, not just a notification?

Yes. The upload bytes can stream straight into the webhook POST body, so the event carries the file itself. With inline transforms on Professional and above, the body can be JSON or XML converted from the uploaded CSV instead of the raw file.

Retire the polling cron job

Spin up a server, register a webhook URL, point a client at it. Uploads notify your app the instant they land — no schedule, no inbox.

Start free — no credit card