Simple FTP ServiceAzure

Azure Event Grid events for completed uploads

Which BlobCreated events fire when a file is uploaded to your Azure storage account, and how to trigger Data Factory, Auto Loader, Snowpipe or your own Event Grid subscriber only on completed files.
Updated September 3, 2026

Many pipelines react to files arriving in Azure Storage by subscribing to the Microsoft.Storage.BlobCreated event - directly through an Event Grid subscription, or indirectly through Azure Data Factory storage event triggers, Databricks Auto Loader in file notification mode, or Snowflake Snowpipe auto-ingest. Which events your account emits, and when, depends on whether the storage account has hierarchical namespace (Data Lake Storage Gen2) enabled.

This guide explains what fires when your Simple FTP Service writes a file to your Azure backend, and how to make sure downstream automation runs only once the upload is complete - not when a zero-byte file first appears.

Which backend does your service use?

Sign in to the DocEvent console and open Simple FTP ServiceYour Services. The Storage type column shows which Azure backend each service writes through:

  • azure/blob - a storage account with a flat namespace (regular Blob Storage)
  • azure/datalake - a storage account with hierarchical namespace enabled (Data Lake Storage Gen2)

The Your Services list - the Storage type column shows azure/blob or azure/datalake per service

You always select "Azure Blob Storage" when creating a service - DocEvent detects hierarchical namespace automatically and stores through the right API for the account, which is why a service can show azure/datalake even though you picked Blob.

Flat namespace accounts (azure/blob) - one event per upload

On a storage account without hierarchical namespace - storage type azure/blob - SFS uploads through the Blob API and commits the file with a single block-list commit. Azure emits one BlobCreated event, at commit time, with data.api set to PutBlockList. When you receive it, the file is complete - there is nothing to filter.

(Other tools writing to the same container may produce PutBlob for small files or CopyBlob for server-side copies - the event schema reference lists the possible data.api values.)

Data Lake Storage Gen2 accounts (azure/datalake) - two events per upload

On an account with hierarchical namespace enabled - storage type azure/datalake - SFS automatically uses the Data Lake (DFS) API. A Data Lake upload happens in stages: the file is created, data is appended, and the file is finally flushed with close to mark it complete. Azure Event Grid only announces two of those stages - CreateFile and FlushWithClose - so one completed upload produces two BlobCreated events:

  1. data.api: "CreateFile" - the file now exists in the namespace, with zero bytes of content
  2. data.api: "FlushWithClose" - the upload is complete and the content is final

The CreateFile event cannot be suppressed - file creation is a namespace operation on Data Lake Storage, and Azure always announces it. This two-event pattern is not specific to DocEvent: it is what every well-behaved Data Lake writer produces, including the Spark/Hadoop ABFS driver used by Databricks, Synapse and Fabric.

Act only on FlushWithClose

If your subscriber must only see completed files, filter on data.api. This is Microsoft's own recommendation, and the managed integrations already follow it: Data Factory storage event triggers, Auto Loader file notification mode and Snowpipe auto-ingest all ignore CreateFile and act on FlushWithClose.

For your own Event Grid subscription, add an advanced filter on data.api. Including the Blob API commit values as well makes one filter correct for both account kinds - and for files written to the same container by blob-endpoint tools such as azcopy, the Azure portal or Storage Explorer:

"advancedFilters": [
  {
    "operatorType": "StringIn",
    "key": "data.api",
    "values": ["FlushWithClose", "PutBlockList", "PutBlob"]
  }
]

With this filter in place, every event you receive represents a file whose content is complete.

If files never trigger downstream processing

A writer that flushes a Data Lake file without the close flag produces no FlushWithClose event at all - Azure does not emit an event for a plain flush, so the only BlobCreated such an upload ever produces is the zero-byte CreateFile. Unfiltered subscribers fire while the file is still empty, and consumers that (correctly) filter on FlushWithClose never fire.

This missing-close trap is common across the ecosystem, so if a writer in your pipeline produces files that never trigger downstream processing, check whether it flushes with close. Microsoft's own Data Lake SDK convenience upload defaults Close to false, the same pattern exists in several Apache NiFi and Kafka Connect sinks, and Databricks documents Auto Loader not picking up files written by an Azure Function for exactly this reason. The Path - Update API reference describes the flush close parameter and the event it controls.