# API Library
Source: https://docs.filefeed.io/api-library/overview
TypeScript SDK for programmatic access to FileFeed
## Overview
The `@filefeed/sdk` package provides a type-safe client for the FileFeed API.
* Authentication via API key
* Resources: Connections (formerly Clients), Pipelines, Schemas, Pipeline Runs, Webhooks, Outbound Uploads, Documents, Files, Notifications
* Pagination helpers and typed responses
## Quick links
Explore endpoints with the API Playground.
Fetch processed data and acknowledge runs.
Retry patterns and structured error handling.
## Installation
```bash theme={null}
npm install @filefeed/sdk
```
```bash theme={null}
yarn add @filefeed/sdk
```
```bash theme={null}
pnpm add @filefeed/sdk
```
## Requirements
* Node.js >= 18
* TypeScript >= 5 (for TS projects)
## Initialize the client
```ts theme={null}
import FileFeed from '@filefeed/sdk';
const filefeed = new FileFeed({ apiKey: process.env.FILEFEED_API_KEY! });
// Example usage
const runs = await filefeed.pipelineRuns.list({ status: 'completed', limit: 50 });
```
## Next steps
* Call endpoints with the [API Reference](/api-reference/introduction)
## Resources and methods
For endpoint details and payload schemas, see the API Reference.
Manage SFTP / Email endpoints (formerly called *clients*). The deprecated
`filefeed.clients.*` namespace still works and proxies here.
| Method | Signature | Description |
| --------- | -------------------- | ------------------------------------------------------------------------------------------- |
| list | `list()` | List connections. |
| retrieve | `retrieve(id)` | Get a connection by id. |
| getByName | `getByName(name)` | Get a connection by name (unique per workspace). Resolves to the connection or `undefined`. |
| create | `create(params)` | Create a connection (SFTP, self-hosted SFTP, or `type: 'EMAIL'`). |
| update | `update(id, params)` | Update connection details. |
| remove | `remove(id)` | Delete a connection. |
| test | `test(id)` | Test SFTP connectivity (returns success/message). No-op for EMAIL. |
**Common workflows**
* Provision a connection with SFTP credentials (write-only — never read back)
* Create an EMAIL connection that ingests mailed attachments
* Verify connectivity before onboarding
* Resolve a connection by its human-readable name
```ts theme={null}
const conn = await filefeed.connections.create({ name: 'Acme' });
const ok = await filefeed.connections.test(conn.id);
// Outbound uploads reference a connection by its human-readable NAME —
// pass `connectionName: 'Acme'` directly (no slug lookup needed).
// Credentials are never returned on reads.
const found = await filefeed.connections.getByName('Acme');
if (found) console.log(found.id, found.sftpUsername);
```
Define and validate your target data model.
| Method | Signature | Description |
| -------- | ------------------------------ | ------------------------------------------------ |
| list | `list()` | List schemas. |
| retrieve | `retrieve(id)` | Get a schema. |
| create | `create(params)` | Create a schema from a JSON Schema `definition`. |
| update | `update(id, params)` | Update a schema's `definition`. |
| remove | `remove(id)` | Delete a schema. |
| validate | `validate({ schemaId, data })` | Validate a payload against a schema. |
**Common workflows**
* Define the column structure as a JSON Schema `definition`
* Validate a sample payload pre-ingestion
```ts theme={null}
const schema = await filefeed.schemas.create({
name: 'Employees',
definition: {
type: 'object',
properties: {
email: { type: 'string' },
name: { type: 'string' },
},
required: ['email', 'name'],
},
});
const result = await filefeed.schemas.validate({ schemaId: schema.id, data: { email: 'a@b.com', name: 'Ada' } });
```
Connect clients to schemas and define mappings/transforms. Field mappings
support sourced entries (`{ source, target, transform? }`), static values
(`{ target, value }`) that write a fixed constant into a column on every row,
and aggregated entries (`{ sources, target, delimiter? }`) that join several
input columns into one target — limited availability, see
[field-mapping kinds](/automated-flows/sftp).
| Method | Signature | Description |
| ------------ | -------------------------------------- | ---------------------------------------- |
| list | `list({ clientId?, connectionName? })` | List pipelines. |
| retrieve | `retrieve(id)` | Get a pipeline. |
| create | `create(params)` | Create a pipeline (mappings/transforms). |
| update | `update(id, params)` | Update pipeline configuration. |
| remove | `remove(id)` | Delete a pipeline. |
| toggleActive | `toggleActive(id)` | Enable/disable a pipeline. |
**Common workflows**
* Create a pipeline for a client + schema
* Adjust mappings, then toggle active for go-live
```ts theme={null}
const pipeline = await filefeed.pipelines.create({
name: 'Employees',
clientId,
schemaId,
mappings: {
fieldMappings: [
{ source: 'emp_id', target: 'id' },
{ target: 'source_system', value: 'FileFeed' }, // static constant on every row
],
},
});
await filefeed.pipelines.toggleActive(pipeline.id);
```
Manage processing jobs and retrieve processed data.
| Method | Signature | Description |
| ------------------- | ------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| list | `list({ status?, clientId?, pipelineId?, pipelineName?, page?, limit? })` | Paginated runs. Filter by status/client/pipeline/ids. |
| retrieve | `retrieve(id)` | Get a single pipeline run. |
| getData | `getData({ pipelineRunId, offset?, limit? })` | Paginated processed rows (offset-based, up to 1000 per page). |
| ack | `ack({ pipelineRunId })` | Mark run as processed (idempotent). |
| reprocess | `reprocess({ pipelineRunId })` | Re-run processing for a given run. |
| getOriginalFileUrl | `getOriginalFileUrl({ pipelineRunId, expiresIn? })` | Presigned URL to the original file. |
| getProcessedFileUrl | `getProcessedFileUrl({ pipelineRunId, expiresIn? })` | Presigned URL to the processed file. |
| delta | `delta({ baseRunId, compareRunId, offset?, limit? })` | Compare two runs of the **same** pipeline; returns the records added/removed between their processed files, with summary counts and a paginated `changes` list. |
**Common workflows**
* Fetch completed runs, paginate data, then acknowledge the run
* Download original or processed file for audit trails
* Reprocess failed runs after fixing mapping or schema
* Diff two runs of the same pipeline (e.g. yesterday vs today) to see which records changed
```ts theme={null}
// Quick example
const runs = await filefeed.pipelineRuns.list({ status: 'completed', limit: 25 });
const page = await filefeed.pipelineRuns.getData({ pipelineRunId: runs.data[0].id, limit: 1000 });
// Compare the two most recent runs of the same pipeline
const diff = await filefeed.pipelineRuns.delta({
baseRunId: runs.data[1].id,
compareRunId: runs.data[0].id,
});
console.log(diff.summary); // { baseCount, compareCount, addedCount, removedCount }
```
Receive signed notifications for pipeline events.
| Method | Signature | Description |
| ---------------------------------- | ------------------------ | ------------------------------------------------------------------------------------------------------------- |
| list | `list()` | List webhooks. |
| retrieve | `retrieve(id)` | Get a webhook. |
| create | `create(params)` | Create a webhook (name, URL, optional headers). eventType defaults to GENERAL and secret is server-generated. |
| update | `update(id, params)` | Update webhook configuration. |
| remove | `remove(id)` | Delete a webhook. |
| listDeliveries | `listDeliveries(params)` | Inspect delivery attempts and status codes. |
| subscribeZapierPipelineRunEvents | `({ targetUrl })` | Subscribe a Zapier URL to pipeline-run events. |
| unsubscribeZapierPipelineRunEvents | `({ id })` | Remove a Zapier pipeline-run subscription. |
**Common workflows**
* Create a webhook for pipeline events
* Monitor delivery health and retry on failure
```ts theme={null}
const hook = await filefeed.webhooks.create({ name: 'Pipeline events', url: 'https://example.com/webhooks/filefeed' });
const deliveries = await filefeed.webhooks.listDeliveries({ webhookId: hook.id, page: 1, limit: 50 });
```
Push JSON data into outbound pipelines via multipart uploads.
| Method | Signature | Description |
| --------------- | ------------------------------------------ | ----------------------------------------------------- |
| initUpload | `initUpload(params)` | Create an upload session. |
| uploadPart | `uploadPart(uploadId, partNumber, params)` | Upload one JSON array part. |
| completeUpload | `completeUpload(uploadId, params)` | Finalize and trigger processing. |
| abortUpload | `abortUpload(uploadId)` | Cancel and cleanup parts. |
| getUploadStatus | `getUploadStatus(uploadId)` | Check session progress. |
| uploadJson | `uploadJson(params)` | Convenience: chunk, upload, and complete in one call. |
**Common workflows**
* Push data from your backend into a pipeline
* Chunk large datasets and upload in parts
* Use `uploadJson()` for simple one-shot uploads
* Choose the delivered file's name and format (`csv` | `json` | `xml`)
Pass the connection's human-readable `name` as `connectionName` (the legacy `clientName` resolves by that same name and is deprecated).
```ts theme={null}
const result = await filefeed.outbound.uploadJson({
connectionName: 'Acme Corp',
pipelineName: 'employee-sync',
data: [{ remoteId: 'E001', firstName: 'Alice', lastName: 'Smith' }],
outputFilename: 'employees.csv', // optional exact name
outputFormat: 'csv', // optional: csv | json | xml
});
```
See the [Outbound Flow guide](/automated-flows/outbound) for the full walkthrough.
Browse and manage a connection's file store (S3 drive). Paths are relative
to the connection root; pipeline-backed folders are protected.
| Method | Signature | Description |
| ---------------------------------------- | ----------------------------------------- | ------------------------------------- |
| browse | `browse({ connectionId, path?, token? })` | List one page of folders/files. |
| getMetadata | `getMetadata({ connectionId, path })` | File size, content type, etag. |
| getDownloadUrl | `getDownloadUrl({ connectionId, path })` | Presigned download URL. |
| createUploadTicket | `createUploadTicket(params)` | Presigned single/multipart upload. |
| completeUpload / abortUpload | `(params)` | Finalize / cancel a multipart upload. |
| createFolder / move / rename | `(params)` | Folder + path operations. |
| deleteObject / deleteFolder / bulkDelete | `(params)` | Delete (force = admin only). |
```ts theme={null}
const page = await filefeed.documents.browse({ connectionId: 'conn_1' });
console.log(page.folders, page.files);
```
Direct access to processed file content (distinct from per-run access on
`pipelineRuns`).
| Method | Signature | Description |
| ------- | ---------------------------------------------------------------- | ------------------------------------ |
| getJson | `getJson({ clientName, fileName, pipelineId, offset?, limit? })` | Fetch a processed JSON file by name. |
| search | `search({ pipelineRunIds, searchTerm?, ... })` | Search rows across processed files. |
```ts theme={null}
const results = await filefeed.files.search({
pipelineRunIds: ['run_1', 'run_2'],
searchTerm: 'john@example.com',
});
```
Per-connection notification preferences — deliver pipeline-run alerts over
EMAIL / SLACK / SMS.
| Method | Signature | Description |
| -------------- | ----------------------------------------------- | ----------------------------------------------------- |
| getPreferences | `getPreferences(connectionId)` | List a connection's preferences. |
| setPreferences | `setPreferences(connectionId, { preferences })` | Upsert preferences (an enabled one needs recipients). |
```ts theme={null}
await filefeed.notifications.setPreferences('conn_123', {
preferences: [
{ eventType: 'PIPELINE_RUN_FAILED', channel: 'EMAIL', isEnabled: true, recipients: ['ops@acme.com'] },
],
});
```
The `documents`, `files`, and `notifications` resources and the Zapier webhook
methods require **`@filefeed/sdk` ≥ 2.5.0**.
## Example: Paginate Data
```ts theme={null}
const runs = await filefeed.pipelineRuns.list({ status: 'completed', limit: 50 });
for (const run of runs.data) {
let offset: number | null = 0;
do {
const page = await filefeed.pipelineRuns.getData({ pipelineRunId: run.id, limit: 1000, offset });
// process page.data
offset = page.data.length === 1000 ? (offset ?? 0) + page.data.length : null;
} while (offset !== null);
}
```
# Create client
Source: https://docs.filefeed.io/api-reference/clients-deprecated/create-client
/api-reference/openapi.json post /clients
**Deprecated** as of API version `2026-05-25`. Use [`POST /connections`](#tag/connections/post/connections) instead. Sunset: 2027-05-25.
# Delete client
Source: https://docs.filefeed.io/api-reference/clients-deprecated/delete-client
/api-reference/openapi.json delete /clients/{id}
**Deprecated** — use `DELETE /connections/{id}` instead.
# Get client
Source: https://docs.filefeed.io/api-reference/clients-deprecated/get-client
/api-reference/openapi.json get /clients/{id}
**Deprecated** — use `GET /connections/{id}` instead.
# List clients
Source: https://docs.filefeed.io/api-reference/clients-deprecated/list-clients
/api-reference/openapi.json get /clients
**Deprecated** as of API version `2026-05-25`. Use [`GET /connections`](#tag/connections/get/connections) instead. Sunset: 2027-05-25.
# Test SFTP connection
Source: https://docs.filefeed.io/api-reference/clients-deprecated/test-sftp-connection
/api-reference/openapi.json post /clients/{id}/test-connection
**Deprecated** — use `POST /connections/{id}/test-connection` instead.
# Update client
Source: https://docs.filefeed.io/api-reference/clients-deprecated/update-client
/api-reference/openapi.json patch /clients/{id}
**Deprecated** — use `PATCH /connections/{id}` instead.
# Create connection
Source: https://docs.filefeed.io/api-reference/connections/create-connection
/api-reference/openapi.json post /connections
# Delete connection
Source: https://docs.filefeed.io/api-reference/connections/delete-connection
/api-reference/openapi.json delete /connections/{id}
# Get connection
Source: https://docs.filefeed.io/api-reference/connections/get-connection
/api-reference/openapi.json get /connections/{id}
# List connections
Source: https://docs.filefeed.io/api-reference/connections/list-connections
/api-reference/openapi.json get /connections
# Test SFTP connection
Source: https://docs.filefeed.io/api-reference/connections/test-sftp-connection
/api-reference/openapi.json post /connections/{id}/test-connection
Verifies an SFTP connection with a live login. For an EMAIL connection this is a no-op that returns `success: false` with an explanatory message (still HTTP 200, not an error).
# Update connection
Source: https://docs.filefeed.io/api-reference/connections/update-connection
/api-reference/openapi.json patch /connections/{id}
# Abort a multipart upload
Source: https://docs.filefeed.io/api-reference/documents/abort-a-multipart-upload
/api-reference/openapi.json post /documents/upload-abort
# Browse documents
Source: https://docs.filefeed.io/api-reference/documents/browse-documents
/api-reference/openapi.json get /documents/browse
List one page of folders and files under a path within a connection (drive).
# Complete a multipart upload
Source: https://docs.filefeed.io/api-reference/documents/complete-a-multipart-upload
/api-reference/openapi.json post /documents/upload-complete
# Create a folder
Source: https://docs.filefeed.io/api-reference/documents/create-a-folder
/api-reference/openapi.json post /documents/folders
# Create a presigned upload ticket
Source: https://docs.filefeed.io/api-reference/documents/create-a-presigned-upload-ticket
/api-reference/openapi.json post /documents/upload-url
Server picks single (one PUT) or multipart (one PUT per part) based on size.
# Delete a file
Source: https://docs.filefeed.io/api-reference/documents/delete-a-file
/api-reference/openapi.json delete /documents/object
Pass force=true (admin/owner only) to override pipeline-folder protection.
# Delete a folder and its contents
Source: https://docs.filefeed.io/api-reference/documents/delete-a-folder-and-its-contents
/api-reference/openapi.json delete /documents/folder
Pass force=true (admin/owner only) to override pipeline-folder protection.
# Delete multiple items
Source: https://docs.filefeed.io/api-reference/documents/delete-multiple-items
/api-reference/openapi.json post /documents/bulk-delete
Returns the count deleted plus a per-item list of failures — a partial failure does not error.
# Get a presigned download URL
Source: https://docs.filefeed.io/api-reference/documents/get-a-presigned-download-url
/api-reference/openapi.json get /documents/download
# Get document metadata
Source: https://docs.filefeed.io/api-reference/documents/get-document-metadata
/api-reference/openapi.json get /documents/metadata
# Move a file or folder
Source: https://docs.filefeed.io/api-reference/documents/move-a-file-or-folder
/api-reference/openapi.json post /documents/move
# Rename a file or folder
Source: https://docs.filefeed.io/api-reference/documents/rename-a-file-or-folder
/api-reference/openapi.json post /documents/rename
# Get a processed JSON file by name
Source: https://docs.filefeed.io/api-reference/files/get-a-processed-json-file-by-name
/api-reference/openapi.json get /files/json
Retrieve a processed JSON file's content, located by connection name, file name, and pipeline. Supply offset/limit to page an array file.
# Search across processed files
Source: https://docs.filefeed.io/api-reference/files/search-across-processed-files
/api-reference/openapi.json post /files/search
Search rows across processed files belonging to the given pipeline runs. pipelineRunIds is required; omit searchTerm to return all rows.
# API Introduction
Source: https://docs.filefeed.io/api-reference/introduction
Base URL, authentication, versioning, and conventions
## Base URL
```
https://api.sftpsync.io
```
## Authentication
Every request requires a workspace API key sent via header:
```
X-API-Key:
```
## Versioning
FileFeed uses **date-based API versions**, the same pattern Stripe and Twilio
use. Send the version you want to pin to as a header:
```
FileFeed-Version: 2026-05-25
```
If you omit the header, the API falls back to the **default version pinned
to your workspace** (set at signup; configurable from the dashboard). Older
workspaces remain on `2024-09-01` until they explicitly opt in.
### Available versions
| Version | Status | Notes |
| ------------ | ---------- | ----------------------------------------------------------- |
| `2026-05-25` | **Latest** | Renames `Client` → `Connection`. Identical shape, new name. |
| `2024-09-01` | Deprecated | Baseline. Sunsets on **2027-05-25**. |
See the [migration guide](/migration/v1-to-v2) for upgrade instructions and
the [changelog](/changelog) for the full version history.
### Response headers
Every response echoes the version the server applied:
```
FileFeed-Version: 2026-05-25
```
Deprecated routes additionally include:
```
Deprecation: true
Sunset: 2027-05-25
Link: ; rel="deprecation",
; rel="successor-version"
```
Watch for `Deprecation: true` in your integration's response handler — that
header is how you'll know a route you depend on is going away. The
[`@filefeed/sdk`](/api-library/overview) surfaces it through the
`onDeprecation` callback automatically.
## Pagination
* Page-based: `?page=1&limit=50`
* Offset-based (data pages): `?offset=0&limit=1000`
For a typed client, use the `@filefeed/sdk` [API Library](/api-library/overview).
The SDK pins to a specific API version per release, so an SDK upgrade is what
moves you between versions — never an out-of-band wire change.
# Get notification preferences
Source: https://docs.filefeed.io/api-reference/notifications/get-notification-preferences
/api-reference/openapi.json get /notifications/preferences/{clientId}
List a connection's notification preferences, ordered by event type then channel. The path segment is named `clientId` for back-compat — it is the connection id.
# Set notification preferences
Source: https://docs.filefeed.io/api-reference/notifications/set-notification-preferences
/api-reference/openapi.json put /notifications/preferences/{clientId}
Upsert a connection's preferences, matched on (eventType, channel). An enabled preference requires at least one recipient.
# Abort outbound multipart upload and cleanup temp parts
Source: https://docs.filefeed.io/api-reference/outbound-uploads/abort-outbound-multipart-upload-and-cleanup-temp-parts
/api-reference/openapi.json post /outbound/uploads/{uploadId}/abort
Cancels an in-progress upload session, deletes all temporary parts from storage, and marks the session as aborted. Further uploads to this session will be rejected.
# Complete outbound multipart upload and trigger processing
Source: https://docs.filefeed.io/api-reference/outbound-uploads/complete-outbound-multipart-upload-and-trigger-processing
/api-reference/openapi.json post /outbound/uploads/{uploadId}/complete
Combines all uploaded parts into one file, stores it in S3, and triggers pipeline processing. The number of parts listed must match `totalParts`.
# Get outbound multipart upload status
Source: https://docs.filefeed.io/api-reference/outbound-uploads/get-outbound-multipart-upload-status
/api-reference/openapi.json get /outbound/uploads/{uploadId}
Returns the current state of an upload session including which parts have been uploaded.
# Initialize an outbound multipart upload session
Source: https://docs.filefeed.io/api-reference/outbound-uploads/initialize-an-outbound-multipart-upload-session
/api-reference/openapi.json post /outbound/uploads
Creates a new upload session for pushing JSON data into an outbound pipeline. The pipeline must have `direction: "outbound"`.
# Upload one part for an outbound upload session
Source: https://docs.filefeed.io/api-reference/outbound-uploads/upload-one-part-for-an-outbound-upload-session
/api-reference/openapi.json put /outbound/uploads/{uploadId}/parts/{partNumber}
Upload a single part (JSON array of objects). Part numbers are 1-based and must not exceed `totalParts`.
# Acknowledge a pipeline run
Source: https://docs.filefeed.io/api-reference/pipeline-runs/acknowledge-a-pipeline-run
/api-reference/openapi.json patch /pipeline-runs/{id}/status
# Compare two pipeline runs (delta)
Source: https://docs.filefeed.io/api-reference/pipeline-runs/compare-two-pipeline-runs-delta
/api-reference/openapi.json get /pipeline-runs/delta
Compares the processed files of two runs of the SAME pipeline (for example yesterday's ingest vs today's) and returns the records added and removed. The diff is a whole-record multiset difference — the platform has no record-identity key, so a changed row surfaces as one removed plus one added. Both runs must belong to the same pipeline, must be in a processed state (`completed`, `delivered`, or `acknowledged`), and must be visible to the caller. The response carries summary counts plus a single paginated `changes` list (added entries first, then removed).
# Get a pipeline run
Source: https://docs.filefeed.io/api-reference/pipeline-runs/get-a-pipeline-run
/api-reference/openapi.json get /pipeline-runs/{id}
# Get pipeline run data (paginated)
Source: https://docs.filefeed.io/api-reference/pipeline-runs/get-pipeline-run-data-paginated
/api-reference/openapi.json get /files/pipeline-runs/{id}
# Get presigned URL for original file
Source: https://docs.filefeed.io/api-reference/pipeline-runs/get-presigned-url-for-original-file
/api-reference/openapi.json get /files/pipeline-runs/{id}/original
# Get presigned URL for processed file
Source: https://docs.filefeed.io/api-reference/pipeline-runs/get-presigned-url-for-processed-file
/api-reference/openapi.json get /files/pipeline-runs/{id}/processed
# Get runs by pipeline
Source: https://docs.filefeed.io/api-reference/pipeline-runs/get-runs-by-pipeline
/api-reference/openapi.json get /pipeline-runs/pipeline/{pipelineId}
# List pipeline runs
Source: https://docs.filefeed.io/api-reference/pipeline-runs/list-pipeline-runs
/api-reference/openapi.json get /pipeline-runs
# Reprocess a pipeline run
Source: https://docs.filefeed.io/api-reference/pipeline-runs/reprocess-a-pipeline-run
/api-reference/openapi.json post /files/pipeline-runs/{id}/reprocess
# Create pipeline
Source: https://docs.filefeed.io/api-reference/pipelines/create-pipeline
/api-reference/openapi.json post /pipelines
# Delete pipeline
Source: https://docs.filefeed.io/api-reference/pipelines/delete-pipeline
/api-reference/openapi.json delete /pipelines/{id}
# Get pipeline
Source: https://docs.filefeed.io/api-reference/pipelines/get-pipeline
/api-reference/openapi.json get /pipelines/{id}
# List pipelines
Source: https://docs.filefeed.io/api-reference/pipelines/list-pipelines
/api-reference/openapi.json get /pipelines
# Toggle pipeline active status
Source: https://docs.filefeed.io/api-reference/pipelines/toggle-pipeline-active-status
/api-reference/openapi.json patch /pipelines/{id}/toggle-active
# Update pipeline
Source: https://docs.filefeed.io/api-reference/pipelines/update-pipeline
/api-reference/openapi.json patch /pipelines/{id}
# Create schema
Source: https://docs.filefeed.io/api-reference/schemas/create-schema
/api-reference/openapi.json post /schemas
# Delete schema
Source: https://docs.filefeed.io/api-reference/schemas/delete-schema
/api-reference/openapi.json delete /schemas/{id}
# Get schema
Source: https://docs.filefeed.io/api-reference/schemas/get-schema
/api-reference/openapi.json get /schemas/{id}
# List schemas
Source: https://docs.filefeed.io/api-reference/schemas/list-schemas
/api-reference/openapi.json get /schemas
# Update schema
Source: https://docs.filefeed.io/api-reference/schemas/update-schema
/api-reference/openapi.json patch /schemas/{id}
# Validate data against a schema
Source: https://docs.filefeed.io/api-reference/schemas/validate-data-against-a-schema
/api-reference/openapi.json post /schemas/{schemaId}/validate
# Create webhook
Source: https://docs.filefeed.io/api-reference/webhooks/create-webhook
/api-reference/openapi.json post /webhooks
# Delete webhook
Source: https://docs.filefeed.io/api-reference/webhooks/delete-webhook
/api-reference/openapi.json delete /webhooks/{id}
# Get webhook
Source: https://docs.filefeed.io/api-reference/webhooks/get-webhook
/api-reference/openapi.json get /webhooks/{id}
# List webhook deliveries
Source: https://docs.filefeed.io/api-reference/webhooks/list-webhook-deliveries
/api-reference/openapi.json get /webhooks/deliveries
# List webhooks
Source: https://docs.filefeed.io/api-reference/webhooks/list-webhooks
/api-reference/openapi.json get /webhooks
# Subscribe Zapier to pipeline-run events
Source: https://docs.filefeed.io/api-reference/webhooks/subscribe-zapier-to-pipeline-run-events
/api-reference/openapi.json post /webhooks/zapier/pipeline-run-events/subscribe
Registers a workspace-level PIPELINE_RUN_EVENT webhook that fires on every run.
# Unsubscribe Zapier from pipeline-run events
Source: https://docs.filefeed.io/api-reference/webhooks/unsubscribe-zapier-from-pipeline-run-events
/api-reference/openapi.json delete /webhooks/zapier/pipeline-run-events/unsubscribe
# Update webhook
Source: https://docs.filefeed.io/api-reference/webhooks/update-webhook
/api-reference/openapi.json patch /webhooks/{id}
# Email Flow
Source: https://docs.filefeed.io/automated-flows/email
Receive files by email — a dedicated inbound address per connection, with sender, format, and subject controls
The entity formerly called **Client** is now called **Connection** as of API
version `2026-05-25`. This page uses the new name throughout. See the
[migration guide](/migration/v1-to-v2) if you're still on `2024-09-01`.
## What is an Email connection?
An **Email connection** is a [Connection](/automated-flows/sftp#2-connections)
whose `type` is `EMAIL`. Instead of uploading over SFTP, senders **email a file**
to a dedicated inbound address. FileFeed receives the message, validates it, and
runs the first attachment through the connection's pipeline — the same
Schema → Mappings → Transforms → Webhook flow as every other channel.
It's the lowest-friction way to onboard a sender: there are no credentials to
issue. You give them an address, they email files to it.
```
Sender emails a file to {connection}@in.filefeed.io
→ FileFeed validates sender / attachment format / subject
→ Pipeline (Schema + Mappings + Transforms) (first attachment)
→ Processing & Validation
→ Webhook Event (signed)
→ Fetch processed data via API/SDK
```
## Create an email connection
Set `type: "EMAIL"` and configure the inbox. `emailAllowedFormats` is
**required and non-empty** for email connections; the other fields are optional.
```ts theme={null}
import FileFeed from '@filefeed/sdk';
const filefeed = new FileFeed({ apiKey: process.env.FILEFEED_API_KEY! });
const conn = await filefeed.connections.create({
name: 'Acme :: Orders',
type: 'EMAIL',
emailAllowedFormats: ['csv', 'xlsx'], // required & non-empty for EMAIL
emailAllowedSenders: ['@acme.com'], // optional; empty = accept any sender
emailSubjectFilter: 'orders', // optional substring match
});
// The address senders mail files to (server-minted unless you supplied one):
console.log(conn.emailInbox?.inboundAddress);
```
```bash theme={null}
curl -X POST "https://api.sftpsync.io/connections" \
-H "X-API-Key: $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Acme :: Orders",
"type": "EMAIL",
"emailAllowedFormats": ["csv", "xlsx"],
"emailAllowedSenders": ["@acme.com"],
"emailSubjectFilter": "orders"
}'
```
The response includes an `emailInbox` object (present only for `EMAIL`
connections):
```json theme={null}
{
"id": "conn_123",
"name": "Acme :: Orders",
"type": "EMAIL",
"emailInbox": {
"inboundAddress": "feed-7t9w@in.filefeed.io",
"allowedSenders": ["@acme.com"],
"allowedFormats": ["csv", "xlsx"],
"subjectFilter": "orders"
}
}
```
Request fields are prefixed `email*` (`emailAllowedSenders`,
`emailAllowedFormats`, `emailSubjectFilter`, `emailInboundAddress`). The
response returns the same config under `emailInbox` with **short** names
(`allowedSenders`, `allowedFormats`, `subjectFilter`, `inboundAddress`).
## The inbound address
Each email connection has a globally unique **inbound address** — the routing
key mail is delivered to. You can let FileFeed mint one, or supply your own:
* **Server-generated (recommended):** omit `emailInboundAddress` and FileFeed
returns one shaped like `feed-7t9w@in.filefeed.io`.
* **Custom:** pass `emailInboundAddress` shaped as
`{workspace-slug}.{connection-name-slug}@in.filefeed.io` — e.g.
`acme.orders-import@in.filefeed.io` for the workspace `acme`.
Two rules apply to a custom address:
| Condition | Result |
| -------------------------------------------------------- | ----------------- |
| The part before the first `.` is not your workspace slug | `400 Bad Request` |
| The address is already in use by another connection | `409 Conflict` |
The inbound address is **immutable** — it's set at create time and can't be
changed on update. Pick a stable connection name, or use the generated address.
## Configure who can send, and what
These controls are your security boundary — there is no separate credential, so
the allow-list is what keeps an inbox private.
### Allowed senders
`emailAllowedSenders` restricts which `From` addresses are accepted. Each entry
is either a full address or a root-domain pattern:
* `alice@acme.com` — matches that exact address
* `@acme.com` — matches any `*@acme.com` (but **not** subdomains like
`x.acme.com` — list those explicitly)
An **empty or omitted** list accepts **any** sender. Max 50 entries.
### Allowed formats
`emailAllowedFormats` is the attachment **accept-list** and is **required
(non-empty)** for email connections. Accepted values: `csv`, `xlsx`, `xls`,
`json`, `xml`, `tsv`. An attachment whose extension isn't listed is rejected.
This is a configuration-time accept-list and is decoupled from what the
transform parser ultimately supports — accepting a format here doesn't guarantee
downstream transform support for it.
### Subject filter
`emailSubjectFilter` is an optional, case-insensitive **substring** the subject
must contain for the message to be processed (e.g. `orders` matches
`Weekly Orders Export`). Omit it to accept any subject — including an **empty
subject**, which is common for automated senders that just drop a file.
## How inbound ingestion works
When a message arrives, FileFeed:
1. **Routes** it to the connection by the inbound address. An address that
matches no connection is dropped.
2. **Validates the envelope**, in order: allowed senders → attachment format →
subject filter.
3. **Processes the first attachment** through the connection's active inbound
pipeline. (Today only the first attachment is processed; additional
attachments are ignored.)
4. **Emits a signed webhook** on completion, exactly like the SFTP and outbound
flows. See [Webhook Listener](/automated-flows/sftp#webhook-listener) and
[Retrieve processed data](/automated-flows/sftp#retrieve-processed-data) —
the mechanics are identical once a file is in the pipeline.
## Why was my email rejected?
Every rejection (except an unknown inbound address) is recorded as a **failed**
pipeline run, visible in **Dashboard → Pipeline Runs** next to successful ones,
with the reason in the run's error message:
| Reason | What happened |
| --------------------------------------- | --------------------------------------------------------- |
| `Sender ... is not in the allow list` | The `From` address didn't match `emailAllowedSenders` |
| `Attachment format .ext is not allowed` | The attachment's extension isn't in `emailAllowedFormats` |
| `Subject does not match filter "..."` | The subject didn't contain `emailSubjectFilter` |
| `Email contained no attachment` | The message had no attachment to process |
A message sent to an address that matches **no** connection, or to a connection
with no active inbound pipeline, is dropped without a run (there's nothing to
attribute it to).
## Browse received files
Attachments received by an email connection are retained and browsable the same
way as SFTP drives — in the dashboard's **Documents** view for that connection.
## Checklist
* [ ] Get API key (Dashboard → My Account → Security Settings)
* [ ] Create an `EMAIL` connection (set `emailAllowedFormats`; optionally
`emailAllowedSenders` / `emailSubjectFilter`)
* [ ] Note the `emailInbox.inboundAddress` and share it with your sender
* [ ] Define a Schema and create + activate an **inbound** Pipeline on the connection
* [ ] Register a Webhook (store secret, verify signature)
* [ ] Send a test email with an attachment and confirm the run completes
* [ ] Retrieve processed data and persist (SDK or REST)
# Outbound (API) Flow
Source: https://docs.filefeed.io/automated-flows/outbound
Push data into FileFeed programmatically via the outbound multipart upload API
## What is the Outbound Flow?
The **outbound flow** lets you push JSON data into FileFeed through the API instead of uploading files via SFTP. It uses the same pipeline infrastructure — schemas, mappings, transforms, webhooks — but the entry point is an HTTP API call rather than a file drop.
The sender uploads a file to the connection's SFTP space → FileFeed detects and processes it.
Your backend pushes JSON data via API → FileFeed processes it.
## When to use
* You already have the data in your backend and want to push it into a pipeline
* You don't want to manage SFTP connections for a particular data source
* You need programmatic control over when data enters the pipeline
* You're building an integration that produces data (not receives files)
## Prerequisites
Before using the outbound flow, you need:
1. **A Connection** (formerly *Client*) — created in the dashboard or via API. Outbound uploads reference it by its human-readable `name`.
2. **A Schema** — defining the target data structure
3. **An Outbound Pipeline** — with `direction: "outbound"`, linking the connection and schema with field mappings
4. **An API key** — user-type key for authentication
The pipeline **must** have `direction` set to `"outbound"`. Inbound pipelines will be rejected by the upload endpoints.
## Architecture
```
Your Backend
→ POST /outbound/uploads (init session)
→ PUT .../parts/:n (upload JSON chunks)
→ POST .../complete (combine & trigger processing)
→ Pipeline (Schema + Mappings + Transforms)
→ Pipeline Run (status: delivered)
→ Webhook Event (if configured)
→ Fetch processed data via API/SDK
```
## How it works
The outbound upload uses a **multipart flow** similar to AWS S3 multipart uploads:
### Step 1: Initialize
Create an upload session specifying the connection, pipeline, number of parts, and optional filename and output settings.
```ts theme={null}
const init = await filefeed.outbound.initUpload({
connectionName: 'Acme Corp', // the connection's human-readable name
pipelineName: 'employee-sync', // must be direction: "outbound"
totalParts: 3,
filename: 'employees.json', // optional
outputFilename: 'employees.csv', // optional: exact delivered file name
outputFormat: 'csv', // optional: csv | json | xml
});
// init.uploadId → use this for subsequent calls
```
Pass the connection's **human-readable name** as `connectionName` — the same name you created the connection with (e.g. `'Acme Corp'`). The legacy `clientName` field resolves by that same connection name and is deprecated; prefer `connectionName`. Output resolution: `outputFormat` → extension of `outputFilename` → input filename (defaults to JSON).
### Step 2: Upload parts
Upload each part as a JSON array of objects. Parts are numbered 1 through `totalParts`.
```ts theme={null}
await filefeed.outbound.uploadPart(init.uploadId, 1, {
data: [
{ remoteId: 'E001', firstName: 'Alice', lastName: 'Smith' },
{ remoteId: 'E002', firstName: 'Bob', lastName: 'Jones' },
],
});
await filefeed.outbound.uploadPart(init.uploadId, 2, {
data: [
{ remoteId: 'E003', firstName: 'Charlie', lastName: 'Brown' },
],
});
// ... upload remaining parts
```
Each part's `data` must be a JSON array. Parts can have different sizes. The objects should contain the **source** field names that match your pipeline's field mappings. Static-value mappings (`{ target, value }`) need no source field in your data — FileFeed writes the constant into the output automatically.
### Step 3: Complete
Finalize the upload by listing all parts. FileFeed combines them into one file, stores it in S3, and triggers pipeline processing.
```ts theme={null}
const result = await filefeed.outbound.completeUpload(init.uploadId, {
parts: [
{ partNumber: 1 },
{ partNumber: 2 },
],
});
// result.message → "Upload ... completed. Processing started for employees.json"
```
### Step 4: Consume results
After processing completes, a **pipeline run** is created. Outbound runs reach the terminal status `delivered` once the output has been written to its destination (inbound runs use `completed`). Use the standard pipeline runs API to fetch results:
```ts theme={null}
const runs = await filefeed.pipelineRuns.list({
pipelineName: 'employee-sync',
status: 'delivered',
limit: 1,
});
const data = await filefeed.pipelineRuns.getData({
pipelineRunId: runs.data[0].id,
});
console.log(data.data); // transformed records
// Acknowledge when done
await filefeed.pipelineRuns.ack({ pipelineRunId: runs.data[0].id });
```
## Quick path: `uploadJson` helper
For most use cases, the SDK provides a convenience method that handles chunking, part uploads, and completion in one call:
```ts theme={null}
import FileFeed from '@filefeed/sdk';
const filefeed = new FileFeed({ apiKey: process.env.FILEFEED_API_KEY! });
const result = await filefeed.outbound.uploadJson({
connectionName: 'Acme Corp',
pipelineName: 'employee-sync',
data: [
{ remoteId: 'E001', firstName: 'Alice', lastName: 'Smith', workEmail: 'alice@acme.com' },
{ remoteId: 'E002', firstName: 'Bob', lastName: 'Jones', workEmail: 'bob@acme.com' },
// ... any number of records
],
chunkSize: 1000, // records per part (default: 1000)
filename: 'employees.json', // optional
outputFilename: 'employees.csv',// optional: exact delivered file name
outputFormat: 'csv', // optional: csv | json | xml
});
```
## Checking upload status
At any point during the upload, you can check progress:
```ts theme={null}
const status = await filefeed.outbound.getUploadStatus(uploadId);
// status.status → "initiated" | "uploading" | "completed" | "aborted"
// status.uploadedParts → number of parts uploaded so far
// status.totalParts → total expected
```
## Aborting an upload
Cancel an in-progress upload and clean up temporary parts:
```ts theme={null}
await filefeed.outbound.abortUpload(uploadId);
```
After aborting:
* All temporary part data is deleted from storage
* The session is marked as `aborted`
* Further uploads to this session are rejected
## API endpoints
| Method | Endpoint | Description |
| ------ | ----------------------------------------------- | ------------------------------- |
| `POST` | `/outbound/uploads` | Initialize upload session |
| `PUT` | `/outbound/uploads/:uploadId/parts/:partNumber` | Upload one part |
| `POST` | `/outbound/uploads/:uploadId/complete` | Complete and trigger processing |
| `POST` | `/outbound/uploads/:uploadId/abort` | Abort and cleanup |
| `GET` | `/outbound/uploads/:uploadId` | Get upload status |
## Upload states
```
initiated → uploading → completed
↘ aborted
```
| State | Meaning |
| ----------- | ---------------------------------------- |
| `initiated` | Session created, no parts uploaded yet |
| `uploading` | At least one part has been uploaded |
| `completed` | All parts combined, processing triggered |
| `aborted` | Upload cancelled, parts cleaned up |
## Integration checklist
* [ ] Create Connection with SFTP credentials (its name is the `connectionName` you pass to outbound uploads)
* [ ] Define Schema (target fields and validation)
* [ ] Create Pipeline with `direction: "outbound"` (link connection + schema, define mappings)
* [ ] Get API key (Dashboard → My Account → Security Settings)
* [ ] Push data using `uploadJson()` or the manual multipart flow
* [ ] Poll or listen for pipeline run completion
* [ ] Fetch processed data and persist to your system
* [ ] Acknowledge the pipeline run
The outbound flow uses the same pipeline runs, webhooks, and data retrieval as the SFTP flow. The only difference is how data enters the system.
# Overview
Source: https://docs.filefeed.io/automated-flows/overview
Learn about FileFeed's automated file processing workflows
## What are Automated Flows?
Automated Flows allow you to set up file processing workflows that run automatically without manual intervention. Files are processed based on triggers like file uploads, scheduled intervals, or external system events.
## Key Benefits
Set up once and let FileFeed handle file processing automatically.
Process files based on uploads, schedules, or external events.
Handle large volumes of files with automatic scaling.
Connect with SFTP, APIs, and other external systems.
## How it Works
1. **Configure the Flow** - Set up your processing rules and triggers
2. **Define Input Sources** - Specify where files come from (SFTP, API, etc.)
3. **Set Processing Rules** - Define how files should be processed
4. **Configure Outputs** - Specify where processed data should go
5. **Monitor & Manage** - Track processing status and manage flows
## Supported Integrations
* **SFTP (Inbound)** - Senders upload files to dedicated SFTP folders per connection
* **Email (Inbound)** - Senders email files to a dedicated inbound address per connection; FileFeed validates the message and runs the attachment through the pipeline
* **API (Outbound)** - Your backend pushes JSON data via the multipart upload API
* **Webhooks** - Receive notifications when files are processed
* **Cloud Storage** - Coming soon
## Flow Types
### Scheduled Flows
Process files at regular intervals (hourly, daily, weekly, etc.)
### Event-driven Flows
Process files when specific events occur (file upload, API call, etc.)
### Continuous Flows
Monitor directories or endpoints continuously for new files
## Architecture
### Inbound (SFTP)
```
SFTP Upload (per Connection)
→ FileFeed SFTP
→ Pipeline (Schema + Mappings + Transforms)
→ Processing & Validation
→ Webhook Event (signed)
→ Fetch processed data via API/SDK
→ Persist to your DB
```
### Inbound (Email)
```
Sender emails a file to {connection}@in.filefeed.io
→ FileFeed receives the message
→ Validate sender / attachment format / subject
→ Pipeline (Schema + Mappings + Transforms) (first attachment)
→ Processing & Validation
→ Webhook Event (signed)
→ Fetch processed data via API/SDK
→ Persist to your DB
```
A rejected message (sender not allow-listed, disallowed attachment format,
subject-filter miss, or no attachment) is recorded as a **failed** pipeline run
so it's visible in **Dashboard → Pipeline Runs** alongside successful ones — see
[Email Flow](/automated-flows/email).
### Outbound (API)
```
Your Backend
→ POST /outbound/uploads (init)
→ PUT .../parts/:n (upload JSON chunks)
→ POST .../complete (combine & trigger)
→ Pipeline (Schema + Mappings + Transforms)
→ Processing & Validation
→ Webhook Event (signed)
→ Fetch processed data via API/SDK
→ Persist to your DB
```
Respond quickly to webhooks and process asynchronously (queue/worker). Use the SDK to fetch full data pages.
## Next Steps
Inbound: SFTP setup, webhooks, monitoring.
Inbound: email files to a dedicated address; sender/format/subject rules.
Push JSON data via API multipart uploads.
Use the TypeScript SDK to sync data.
### Checklist
* [ ] Create Connection (SFTP / self-hosted SFTP / Email)
* [ ] Define Schema (JSON Schema `definition`)
* [ ] Create Pipeline (mappings & transforms; set `direction` to `inbound` or `outbound`)
* [ ] Register Webhook (store secret, verify signature)
* [ ] Upload data via SFTP (inbound) or API (outbound)
* [ ] Fetch processed data and persist
# SFTP Flow
Source: https://docs.filefeed.io/automated-flows/sftp
Complete guide to integrating with FileFeed through SFTP, webhooks, and REST API
The entity formerly called **Client** is now called **Connection** as of API
version `2026-05-25`. Legacy `/clients` endpoints and `Client` types remain
available — see the [migration guide](/migration/v1-to-v2). This page uses
the new name throughout; if you're still on `2024-09-01`, mentally substitute
"client" wherever you see "connection".
## SFTP Integration
FileFeed provides a comprehensive SFTP-based integration platform that automates
file-based workflows by receiving, validating, transforming, and routing structured
data files. This section covers all aspects of SFTP integration including core
concepts, webhook listeners, REST API access, and implementation checklists.
## Core Concepts
Understanding the fundamental concepts of FileFeed platform is essential for
successful integration. This section explains how connections, schemas, and pipelines
work together to automate your file processing workflows.
### 1. Platform Overview
FileFeed is designed to solve the challenge of managing file transfers and data
integrations across multiple data sources, systems, and file formats. It provides a
centralized platform where you can:
* Create dedicated SFTP spaces for each connection (data source)
* Define schemas that validate incoming data files
* Build automated pipelines that transform files into standardized formats
* Send processed data to destination systems via webhooks or API
* Monitor file processing and alert on errors
### 2. Connections
In FileFeed, a **Connection** (formerly called *Client*) represents one
data-source endpoint — typically an organization or business entity that
sends files to FileFeed via SFTP. Each connection has:
* **Dedicated SFTP space**: A secure
environment where the data source can upload files
* **SFTP credentials**: Username and
password for connecting to the SFTP server
* **SFTP host**: The server address
displayed on the connection's page for connection
* **Connection ID**: A unique identifier
used in API calls and data routing
* **Associated pipelines**: Workflows
that process files uploaded into this connection
Connections are isolated from each other, ensuring data privacy and security.
They connect to their dedicated SFTP space using their assigned username and
password with the host specified on the connection's configuration page.
```json theme={null}
// Example connection object (v1 callers may see this returned as a `client`).
// Credentials (sftpPassword / sftpPrivateKey / sftpPassphrase / awsPassword)
// are write-only and never returned on reads.
{
"id": "c4b3f495-5dfc-4a91-b604-a8e66ab4a220",
"name": "Acme Logistics Inc.",
"type": "SFTP",
"sftpUsername": "acme_sftp",
"useHostedSFTP": true,
"awsUserName": "ws-acme-logi-7t9w",
"sftpServer": {
"id": "srv_123",
"host": "sftp.sftpsync.io",
"port": 22,
"isAwsHosted": true,
"status": "active"
},
"createdAt": "2023-05-15T10:30:00Z",
"updatedAt": "2023-06-01T08:45:22Z"
}
```
**FileFeed-hosted vs self-hosted SFTP.** Set `useHostedSFTP: true` (default) to
have FileFeed provision the SFTP server. For a **self-hosted** connection
(`useHostedSFTP: false`) FileFeed dials out to your own server — supply
`sftpHost`, `sftpPort`, `sftpRemotePath`, and credentials on create/update.
### 3. Schemas
A **Schema** defines the structure and
validation rules for data files. It specifies:
* **Fields**: The columns or properties
expected in the data
* **Data types**: The expected type for
each field (string, number, date, etc.)
* **Validation rules**: Requirements for
each field (required/optional, format, range, etc.)
Schemas help ensure data quality by rejecting files that don't meet your
specifications. They define what data is expected and its format, but do not
handle transformations (which are handled separately by pipelines).
```json theme={null}
// Example schema definition
{
"schemaId": "ord-schema-v1",
"name": "Order Schema v1",
"fileType": "csv",
"fields": [
{
"name": "order_id",
"type": "string",
"required": true,
"validation": {
"pattern": "^ORD-[0-9]{6}$"
}
},
{
"name": "customer_email",
"type": "string",
"required": true,
"validation": {
"format": "email"
}
},
{
"name": "order_date",
"type": "date",
"required": true,
"sourceFormat": "MM/DD/YYYY",
"targetFormat": "YYYY-MM-DD"
},
{
"name": "total_amount",
"type": "number",
"required": true,
"validation": {
"min": 0
}
}
]
}
```
The JSON above illustrates the **concept** of a schema. Over the API a schema's
structure is supplied as a single JSON Schema `definition` object (`{ type,
properties, required }`) — see the [Schema endpoints](/api-reference/openapi)
and the SDK `schemas.create({ name, definition })` example. The legacy `fields`
array is not used by the API.
### 4. Pipelines
A **Pipeline** in FileFeed defines how
files are processed when uploaded to a specific folder. Each pipeline includes:
* **Schema**: The file structure we're
mapping to (defines expected data format)
* **Webhook**: Optional notification when
new files are uploaded
* **Starter file**: Template that defines
the expected header structure for Excel/CSV files
* **Mappings**: Column mappings (both
automatic and manual) from source to target schema
* **Transformations**: Data manipulations
that can be applied to specific columns
Each pipeline creates a dedicated folder in the connection's SFTP space. When a file
is uploaded to this folder, it automatically triggers the processing based on the
defined mappings and transformations.
```json theme={null}
// Example pipeline configuration
{
"options": {
"delimiter": ",",
"skipHeaderRow": true
},
"fieldMappings": [
{
"source": "customer_id",
"target": "id"
},
{
"source": "customer_name",
"target": "name"
},
{
"source": "customer_email",
"target": "email",
"transform": "toLowerCase"
},
{
"source": "customer_phone",
"target": "phone",
"transform": "formatPhoneNumber"
}
],
"transformations": {
"toLowerCase": "function(value) { return value.toLowerCase(); }",
"formatPhoneNumber": "function(value) { return value.replace(/[^0-9]/g, ''); }"
}
}
```
Each entry in `fieldMappings` is one of three kinds:
* **Sourced** — `{ "source": "...", "target": "...", "transform": "..." }` copies a column from the input into the target field.
* **Static value** — `{ "target": "...", "value": "..." }` writes a fixed constant into the target field on **every row**, regardless of the input. Omit `source` and provide `value` instead. Useful for stamping metadata that isn't in the file (a source system, region, batch tag). Transforms don't apply to a static value — the constant is written verbatim. Works in both inbound and outbound pipelines.
* **Aggregated** — `{ "sources": ["...", "..."], "target": "...", "delimiter": " " }` joins **several** input columns into one target field, in order, joined by `delimiter` (default a single space), skipping empty values so the delimiter never dangles. Provide `sources` instead of `source`. A `transform`, if set, runs on the joined result.
```json theme={null}
// A static value alongside sourced mappings
{
"fieldMappings": [
{ "source": "customer_id", "target": "id" },
{ "target": "source_system", "value": "FileFeed" }
]
}
```
```json theme={null}
// Combine first + last name into one column
{
"fieldMappings": [
{ "sources": ["first_name", "last_name"], "target": "full_name", "delimiter": " " }
]
}
```
Aggregated (multi-source) mappings are in **limited availability** and must be
enabled for your workspace. Until then, saving a pipeline that uses `sources`
returns `400`. Contact [support@filefeed.io](mailto:support@filefeed.io) to
enable the field-aggregation feature.
### 5. Typical Workflow
Here's a typical workflow in FileFeed that illustrates how connections,
schemas, and pipelines work together:
1. **Connection Setup**: You create a new
connection in FileFeed, which generates SFTP credentials and a dedicated SFTP space.
2. **Schema Definition**: You define a
schema that specifies the target data structure you want to receive after
processing.
3. **Pipeline Creation**: You create a
pipeline and associate it with the schema. This automatically creates a
dedicated folder in the connection's SFTP space.
4. **Starter File Setup**: You upload a
template file with the expected header structure for the files the
sending team will upload.
5. **Field Mapping**: You define mappings
between source columns in the uploaded files and target fields in your schema.
6. **Transformation Setup**: You create
JavaScript transformation functions to apply to specific fields.
7. **Webhook Configuration**: You set up
an optional webhook URL to receive notifications when files are processed.
8. **File Upload**: The sender uploads a
file to the dedicated pipeline folder in the SFTP space.
9. **Automatic Processing**: FileFeed
detects the new file, applies the defined mappings and transformations.
10. **Notification**: If a webhook is
configured, a notification is sent to the specified URL.
## Webhook Listener
When files are processed in FileFeed, our system can notify your application
through webhooks. Follow these steps to implement a webhook listener:
### 1. Understanding Webhooks
FileFeed webhooks send HTTP POST requests to your specified endpoint when
certain events occur:
* **GENERAL:** Sent for all file processing events, including
successful processing and error situations
### 2. Webhook Request Structure
Below is an example of the JSON payload sent to your webhook endpoint.
```json theme={null}
{
"event": "GENERAL",
"timestamp": "2025-05-19T21:30:00.000Z",
"data": {
"fileId": "550e8400-e29b-41d4-a716-446655440000",
"filename": "example_data.csv",
"clientName": "acme_inc",
"status": "completed",
"processedFilename": "example_data_processed.csv",
"jsonFilename": "example_data.json",
"size": 24680,
"processedAt": "2025-05-19T21:29:55.000Z"
}
}
```
### 3. Webhook Security
All webhook requests include a signature to verify authenticity:
* Requests contain an `x-sftpsync-signature` header
* The signature is an HMAC-SHA256 hash of the request body using your webhook secret
* The secret can be found in the webhook configuration section of your dashboard (Dashboard -> Webhooks -> Configuration -> View Configuration button -> Get secret)
### 4. Example (Node.js)
Here's a basic Node.js example using Express to listen for FileFeed webhooks
and verify their signatures.
```javascript theme={null}
const express = require('express');
const crypto = require('crypto');
const app = express();
app.use(express.json());
const WEBHOOK_SECRET = 'your_webhook_secret';
function verifySignature(requestPayload, signature) {
const hmac = crypto.createHmac('sha256', WEBHOOK_SECRET);
const digest = hmac.update(JSON.stringify(requestPayload)).digest('hex');
return crypto.timingSafeEqual(
Buffer.from(digest),
Buffer.from(signature)
);
}
app.post('/webhooks/sftpsync', (req, res) => {
const signature = req.headers['x-sftpsync-signature'];
const requestBody = req.body;
if (!signature || !verifySignature(requestBody, signature)) {
return res.status(401).send('Invalid signature');
}
const event = requestBody.event;
switch (event) {
case 'GENERAL': {
const { filename, status } = requestBody.data;
console.log(`File ${filename} event received with status: ${status}`);
if (status === 'completed') {
console.log(`File ${filename} processed successfully`);
} else if (status === 'failed') {
const errorMessage = requestBody.data.errorMessage || 'Unknown error';
console.log(`File ${filename} processing failed: ${errorMessage}`);
}
break;
}
default:
console.log(`Unknown event type: ${event}`);
}
res.status(200).send('Webhook received');
});
app.listen(3000, () => {
console.log('Webhook listener running on port 3000');
});
```
### 5. Best Practices
* Respond quickly (within 5 seconds) to avoid webhook timeouts
* Implement idempotency to handle potential duplicate webhook deliveries
* Use a queue system for processing webhook data asynchronously
* Store your webhook secret securely
* Implement proper error handling
## Retrieve processed data
Use either the TypeScript SDK or the REST API to fetch processed JSON rows for a pipeline run.
```ts theme={null}
import FileFeed from '@filefeed/sdk';
const filefeed = new FileFeed({ apiKey: process.env.FILEFEED_API_KEY! });
// Get recent completed runs, then paginate data for a run
const runs = await filefeed.pipelineRuns.list({ status: 'completed', limit: 25 });
for (const run of runs.data) {
let offset: number | null = 0;
do {
const page = await filefeed.pipelineRuns.getData({ pipelineRunId: run.id, limit: 1000, offset });
// process page.data
offset = page.data.length === 1000 ? (offset ?? 0) + page.data.length : null;
} while (offset !== null);
// Acknowledge once persisted
await filefeed.pipelineRuns.ack({ pipelineRunId: run.id });
}
```
```bash theme={null}
curl -X GET "https://api.sftpsync.io/files/pipeline-runs/run_123?offset=0&limit=1000" \
-H "X-API-Key: $API_KEY"
```
Example response:
```json theme={null}
{
"data": [ { "id": "123", "email": "a@b.com" } ],
"metadata": {
"pipelineRunId": "run_123",
"offset": 0,
"limit": 1000,
"hasMore": false
}
}
```
Finding the pipeline run ID:
* In the app: Dashboard → Pipeline Runs
* Via webhook: included in webhook payloads
All requests require an API key. Store it securely and never commit it.
## Integration Checklist
Use this checklist to ensure your FileFeed integration is properly configured
and ready for production use.
### Step-by-step
* [ ] Get API key (Dashboard → My Account → Security Settings)
* [ ] Create Connection (SFTP credentials)
* [ ] Define Schema (fields, validation)
* [ ] Create Webhook (Dashboard → Webhooks)
* [ ] Create and activate Pipeline (link connection + schema; mappings/transforms)
* [ ] [Register Webhook](/automated-flows/sftp-flow#4-example-node-js) ([store secret; verify HMAC signature](/automated-flows/sftp-flow#3-webhook-security))
* [ ] Upload a sample file and confirm run "completed"
* [ ] Retrieve processed data and persist (SDK or REST)
* [ ] Acknowledge the pipeline run (OPTIONAL)
* [ ] Monitor runs and webhook deliveries; set alerts
Once you've completed all items in this checklist, your FileFeed integration
should be ready for production use.
# Changelog
Source: https://docs.filefeed.io/changelog
API version history and breaking-change log
FileFeed uses date-based API versions. Every entry below is a version you
can pin to via the `FileFeed-Version` header. Existing integrations stay on
their pinned version forever (until that version's sunset date) — bumping
is opt-in.
See the [API introduction](/api-reference/introduction#versioning) for how
versioning works and the [migration guides](#migration-guides) below for
upgrade walkthroughs.
***
## `2026-05-25` Latest
The "Connection" rename.
### Added
* New canonical endpoints under `/connections/*` mirroring the existing
`/clients/*` routes one-for-one.
* `FileFeed-Version` response header on every reply so clients can audit
which shape the server applied.
* `Deprecation` / `Sunset` / `Link` response headers on legacy `/clients`
routes when accessed with this version (per
[RFC 8594](https://www.rfc-editor.org/rfc/rfc8594) and
[draft-ietf-httpapi-deprecation-header](https://www.ietf.org/archive/id/draft-ietf-httpapi-deprecation-header-08.html)).
* `@filefeed/sdk@2.0.0` published with:
* `filefeed.connections.*` namespace
* `FileFeedConfig.apiVersion` override
* `FileFeedConfig.onDeprecation` callback
* Outbound uploads accept `outputFilename` and `outputFormat` (`csv` |
`json` | `xml`) to control the delivered file's name and serialization.
* Pipeline run status `delivered` — the terminal success state for
**outbound** runs (output written to its destination). Inbound runs still
use `completed`.
* `@filefeed/sdk@2.1.0`: outbound output options, self-hosted SFTP connection
fields, `delivered` status.
* `@filefeed/sdk@2.2.0`: `filefeed.connections.getByName(name)` — resolve a
connection (and its `awsUserName`) by its workspace-unique name.
### Changed
* The entity formerly called `Client` is now called `Connection`. The
database row, IDs, and JSON shape are unchanged — only the name moved.
* Connection names are unique per workspace.
* TypeScript types `Client`, `CreateClientParams`, `UpdateClientParams` are
now aliases for `Connection`, `CreateConnectionParams`,
`UpdateConnectionParams`. Source-compatible — existing code keeps
compiling.
### Deprecated
* HTTP: all `/clients/*` routes when called with `FileFeed-Version:
2026-05-25`. They keep working but emit `Deprecation: true`.
* SDK: `filefeed.clients.*` methods. They proxy to `connections.*` and emit
one warning per method per process.
* Method rename: `filefeed.clients.testConnection(id)` → `filefeed.connections.test(id)`.
### Security
* Connection responses no longer return stored credentials
(`sftpPassword` / `sftpPrivateKey` / `sftpPassphrase` / `awsPassword`).
They are write-only: set via create/update, never read back.
### Sunset
* API version `2024-09-01` is scheduled for sunset on **2027-05-25**.
#### Additive updates (no version bump)
These shipped within `2026-05-25` and are backwards compatible:
* Outbound uploads accept `connectionName` (the connection's human-readable
name) on `POST /outbound/uploads`. Connection resolution now matches the
connection `name` — the same path for hosted and self-hosted SFTP — so the
name you created the connection with now works for self-hosted delivery.
The legacy `clientName` field still works (resolved by name) but is
deprecated; `connectionName` is also returned on the upload status response.
* `/pipelines` and `/pipeline-runs` list endpoints accept a `connectionName`
filter (alias of the deprecated `clientName` filter).
* Fixed: outbound `outputFormat: "csv"` / `"xml"` without an explicit
`outputFilename` now delivers the file in the requested format instead of
silently falling back to JSON.
* `@filefeed/sdk@2.3.0` published with `connectionName` support.
* **Static-value field mappings.** A pipeline field mapping can now be a static
constant `{ target, value }` (no `source`) that writes a fixed value into a
column on every row, alongside the existing sourced `{ source, target,
transform? }` mappings. `@filefeed/sdk@2.3.1`.
* **Email connections.** Create a connection with `type: "EMAIL"` to ingest
files mailed as attachments to a dedicated inbound address
(`connection.emailInbox.inboundAddress`). Configure `emailAllowedFormats`
(required, non-empty), `emailAllowedSenders`, and `emailSubjectFilter`.
Workspace registration is restricted to company email domains.
`@filefeed/sdk@2.4.0`.
* **Documents API** (`/documents/*`). A connection-scoped S3 file manager:
`browse`, `metadata`, `download`, presigned single/multipart upload,
folder create/move/rename, and object/folder/bulk delete. Pipeline-backed
folders are protected (override requires `force` + admin).
* **Per-connection notification preferences**
(`GET`/`PUT /notifications/preferences/:connectionId`). Deliver
`PIPELINE_RUN_FAILED` / `PIPELINE_RUN_SUCCEEDED` alerts over `EMAIL` /
`SLACK` / `SMS`.
* **Direct file access.** `GET /files/json` fetches a processed JSON file by
name; `POST /files/search` searches rows across processed files.
* **Zapier pipeline-run subscriptions.**
`POST`/`DELETE /webhooks/zapier/pipeline-run-events/{subscribe,unsubscribe}`
register a workspace-level `PIPELINE_RUN_EVENT` webhook for Zapier.
* **Schemas** are defined by a JSON Schema `definition` object (the SDK's
legacy `fields` array is ignored by the API). Schema responses always include
`isActive`. Webhook signing secrets are returned only once on create and
never on reads.
* `@filefeed/sdk@2.5.0` published with the `documents`, `notifications`, and
`files` resources, Zapier webhook methods, `Schema.definition`,
`Pipeline.webhooks`, and `PipelineRun.client` / `isPipelineDeleted`.
* **Pipeline run delta.** New endpoint `GET /pipeline-runs/delta` compares the
processed files of two runs of the **same** pipeline (for example yesterday vs
today) and returns the records added and removed, with summary counts and a
paginated `changes` list. The diff is a whole-record set difference — there is
no record-identity key, so a changed row appears as one removed plus one
added. Available as
`filefeed.pipelineRuns.delta({ baseRunId, compareRunId })` in
`@filefeed/sdk@2.7.0`.
* **Aggregated field mappings** limited availability. A pipeline
field mapping can now combine **multiple** source columns into one target —
`{ sources, target, delimiter? }` — joined in order by `delimiter` (default a
single space), skipping empty values; a `transform`, if set, runs on the
joined result. Provide `sources` instead of `source`, alongside the existing
sourced and static-value mappings. Gated per workspace: until the feature is
enabled for you, saving a pipeline that uses `sources` returns `400`. Contact
[support@filefeed.io](mailto:support@filefeed.io) to enable it.
[Read the migration guide →](/migration/v1-to-v2)
***
## `2024-09-01` Deprecated · sunsets 2027-05-25
Baseline. This is the version every workspace was created on prior to the
`2026-05-25` release. No prior changelog entries exist — this is the first
version where date-based versioning was introduced; we backdated the
baseline label to the date of GA so we have a coherent timeline.
### Endpoints
* `/clients/*`, `/schemas/*`, `/pipelines/*`, `/pipeline-runs/*`,
`/webhooks/*`, `/outbound/*`
### Sunset behaviour
On **2027-05-25**, requests sent with `FileFeed-Version: 2024-09-01` will
receive `410 Gone`:
```json theme={null}
{
"error": "api_version_sunset",
"message": "API version 2024-09-01 was sunset on 2027-05-25. Upgrade to 2026-05-25.",
"migration_url": "https://docs.filefeed.io/migration/v1-to-v2"
}
```
***
## Migration guides
* [Upgrade to 2026-05-25](/migration/v1-to-v2) — Client → Connection rename
# Core Concepts
Source: https://docs.filefeed.io/core-concepts
Understand FileFeed fundamentals: Connections, Schemas, Pipelines, Pipeline Runs, and Webhooks
The entity formerly called **Client** was renamed to **Connection** in API
version `2026-05-25`. Old names (`/clients`, `filefeed.clients`, `Client`
type) still work for 12 months — see the [migration guide](/migration/v1-to-v2).
## Overview
FileFeed streamlines file-based integrations through two primary paths:
* **Embedded Importers**: In-app data import experiences (React SDK)
* **Automated Flows**: Backend-driven automation via SFTP (inbound) or API (outbound), with webhooks and SDK
## Compare at a glance
| Aspect | Embedded Importers | Automated Flows |
| ------------ | ------------------------------------- | ------------------------------------------------ |
| Trigger | User-initiated in-app | SFTP upload, API push, or scheduled |
| Typical user | Product/Operations teams | Backend/Integrations teams |
| Data entry | UI mapping, preview, validate | File drop to SFTP or JSON push via API |
| Validation | In-app field + custom rules | Schema validation during processing |
| Processing | Client app | FileFeed pipelines + your backend via webhooks |
| Output | Records to your app | Webhook event + fetch processed data via API/SDK |
| Best for | Self-serve onboarding, ad-hoc imports | Continuous or automated partner feeds |
## Embedded Importers
### What it is
* In-app import experience powered by the React SDK
* Validates and transforms data client-side before sending
### When to use
* Product-led import UX inside your app
* One-off or occasional imports initiated by users
### How it works
1. Render the importer in your app
2. Map/validate fields and preview results
3. Submit to your backend to persist/process
High-level concepts and flow.
Embed the importer in your app.
Workbooks, fields, transforms, validations.
## Automated Flows
### Building Blocks
Dedicated SFTP space and credentials per data source. Previously called "Clients".
Define fields and validation to ensure consistent data.
Connect a Connection + Schema, add mappings and transforms. Supports inbound (SFTP) and outbound (API) directions.
Push JSON data into pipelines via API instead of SFTP.
Per-file processing with status and data retrieval.
Event notifications with signed payloads.
Use webhooks to trigger data syncs. Use the REST API/SDK to fetch full processed data.
## Choosing an Integration Path
Best for product teams who want a beautiful, guided import UX inside their app.
Best for backend integrations, SFTP workflows, or scheduled data ingestion.
# Configuration
Source: https://docs.filefeed.io/embedded-importers/configuration
Configure workbooks, fields, transforms, and validations
## Workbook Configuration
Define your workbook and sheets with fields and options.
```jsx theme={null}
const config = {
name: "Advanced Import",
sheets: [
{
name: "Contacts",
slug: "contacts",
fields: [
{ key: "email", type: "email", label: "Email", required: true, defaultTransform: "toLower" },
{ key: "name", type: "string", label: "Full Name", required: true, defaultTransform: "trim" },
{ key: "phone", type: "string", label: "Phone", defaultTransform: "formatPhone" },
{ key: "salary", type: "number", label: "Salary", defaultTransform: "parseCurrency" }
]
}
],
transformRegistry,
validationRegistry,
};
```
## Transform Registry
Register reusable transforms.
```jsx theme={null}
const transformRegistry = {
trim: (v) => (v == null ? v : String(v).trim()),
toLower: (v) => (v == null ? v : String(v).toLowerCase()),
toUpper: (v) => (v == null ? v : String(v).toUpperCase()),
formatPhone: (v) => {
if (!v) return v;
const cleaned = String(v).replace(/\D/g, "");
return cleaned.length === 10 ? `(${cleaned.slice(0,3)}) ${cleaned.slice(3,6)}-${cleaned.slice(6)}` : v;
},
parseCurrency: (v) => {
if (!v) return v;
const parsed = parseFloat(String(v).replace(/[^0-9.-]/g, ""));
return isNaN(parsed) ? v : parsed;
},
};
```
## Validation Registry
Add custom validations alongside built-ins.
```jsx theme={null}
const validationRegistry = {
domainAllowlist: (value, field, rowIndex, rowData, args) => {
if (!value) return true;
const allowed = args?.allowed || ["company.com"];
const domain = String(value).split("@")[1] || "";
return allowed.includes(domain) || `Email domain '${domain}' is not allowed`;
},
ageRange: (value, field, rowIndex, rowData, args) => {
if (!value) return true;
const age = parseInt(value);
const min = args?.min || 18;
const max = args?.max || 65;
return (age >= min && age <= max) || `Age must be between ${min} and ${max}`;
},
};
```
## Record Hooks
Process each record during import.
```jsx theme={null}
{
const firstName = record.get("firstName");
const lastName = record.get("lastName");
record.set("fullName", `${firstName} ${lastName}`);
return record;
}}
/>
```
Use transforms for field-level normalization and record hooks for cross-field logic.
# Overview
Source: https://docs.filefeed.io/embedded-importers/overview
Learn about FileFeed's embedded importers and how they work
## What are Embedded Importers?
Embedded Importers allow you to integrate file import functionality directly into your web applications. Instead of redirecting users to external pages, you can provide a seamless file import experience within your own UI.
## Key Benefits
Keep users in your application with native-feeling file import components.
Style the importers to match your application's design system.
Process files immediately as they're uploaded with live progress updates.
Support for CSV, Excel, JSON, XML, and many other file formats.
## How it Works
1. **Install the SDK** - Add the FileFeed SDK to your project
2. **Configure the Importer** - Set up the importer with your API key and preferences
3. **Embed the Component** - Add the importer component to your React application
4. **Handle Results** - Process the imported data in your application
## Supported Platforms
* **React** - Full SDK with hooks and components
* **Vue** - Coming soon
* **Angular** - Coming soon
* **Vanilla JavaScript** - Basic integration support
## Next Steps
Get started with our React SDK for embedded importers.
# React SDK
Source: https://docs.filefeed.io/embedded-importers/react-sdk
Integrate FileFeed importers into your React applications
# React Embedding
> Embed FileFeed in React applications
Embed FileFeed in your React application using our React SDK. This provides React components and hooks for seamless data import, mapping, validation, and transformation.
## Installation
```bash theme={null}
npm install @filefeed/react
```
## Basic Implementation
### 1. Wrap Your App
Wrap your application with the `FilefeedProvider`:
```jsx theme={null}
import { FilefeedProvider } from "@filefeed/react";
function App() {
return (
);
}
```
### 2. Add Import Interface
Use the `FilefeedWorkbook` component to create a data import interface:
```jsx theme={null}
import { FilefeedWorkbook } from "@filefeed/react";
function YourComponent() {
const config = {
name: "My Data Import",
sheets: [
{
name: "Users",
slug: "users",
fields: [
{ key: "email", type: "email", label: "Email", required: true },
{ key: "name", type: "string", label: "Name", required: true },
],
},
],
};
const handleImportComplete = (data) => {
console.log('Import completed:', data);
};
return (
Welcome to our app
);
}
```
### 3. Configure Your Import
Set up your data schema and import preferences. No additional credentials required for basic usage.
For configuration options, see [Configuration](./configuration).
## Complete Example
The example below will create a workbook with a contacts sheet. Users can upload CSV/Excel files or manually enter data.
```jsx theme={null}
import React from "react";
import { FilefeedProvider, FilefeedWorkbook } from "@filefeed/react";
function ImportComponent() {
const config = {
name: "Contact Import",
sheets: [
{
name: "Contacts",
slug: "contacts",
fields: [
{ key: "name", type: "string", label: "Name", required: true },
{ key: "email", type: "email", label: "Email", required: true },
{ key: "phone", type: "string", label: "Phone" },
],
},
],
};
const handleImportComplete = (data) => {
console.log(`Imported ${data.length} contacts`);
// Process your data here
};
return (
);
}
function App() {
return (
My Application
);
}
export default App;
```
## Configuration Options
For all configuration options including custom transforms, validations, and advanced settings, see [Advanced Configuration](./advanced-configuration).
## Using Workbook Component
For more control, you can use the `FilefeedWorkbook` component directly with custom configuration:
```jsx theme={null}
import { FilefeedProvider, FilefeedWorkbook } from "@filefeed/react";
const workbookConfig = {
name: "Advanced Import",
sheets: [
{
name: "Products",
slug: "products",
fields: [
{ key: "sku", type: "string", label: "SKU", required: true, unique: true },
{ key: "name", type: "string", label: "Product Name", required: true },
{ key: "price", type: "number", label: "Price", required: true },
{ key: "category", type: "string", label: "Category" },
],
},
],
};
function App() {
return (
);
}
```
## Creating New Workbooks
To create a new Workbook each time:
1. Add a `workbook` configuration object with sheets and fields
2. Optionally configure custom transforms and validations
3. Set up event handlers for data processing
```jsx theme={null}
import { FilefeedProvider, FilefeedWorkbook } from "@filefeed/react";
const workbookConfig = {
name: "User Import",
sheets: [
{
name: "Users",
slug: "users",
fields: [
{ key: "email", type: "email", label: "Email", required: true, unique: true },
{ key: "firstName", type: "string", label: "First Name", required: true },
{ key: "lastName", type: "string", label: "Last Name", required: true },
{ key: "department", type: "string", label: "Department" },
],
},
],
};
function App() {
return (
);
}
```
For detailed workbook configuration, see the [Workbook Configuration Reference](./workbook-configuration).
## Using Hooks for Advanced Control
For more advanced control, you can use the `useFilefeed` hook:
```jsx theme={null}
import { FilefeedProvider, useFilefeed } from "@filefeed/react";
function ImportButton() {
const { openPortal, closePortal } = useFilefeed();
const handleImport = () => {
openPortal();
};
return (
);
}
function App() {
return (
);
}
```
This approach allows you to:
* Control the import interface programmatically
* Add custom event listeners and data processing
* Integrate with your existing UI components
For complete integration examples, see [Integration Examples](./integration-examples).
## TypeScript Support
The React SDK includes full TypeScript support:
```tsx theme={null}
import { FilefeedProvider, FilefeedWorkbook, CreateWorkbookConfig } from "@filefeed/react";
interface Props {
onDataImported?: (data: any[]) => void;
}
function ImportComponent({ onDataImported }: Props) {
const config: CreateWorkbookConfig = {
name: "TypeScript Import",
sheets: [
{
name: "Data",
slug: "data",
fields: [
{ key: "id", type: "string", label: "ID", required: true },
{ key: "value", type: "number", label: "Value" },
],
},
],
};
return (
);
}
```
## Next Steps
* **Advanced Configuration**: [Custom transforms, validations, and advanced options](./advanced-configuration)
* **Package Documentation**: See [@filefeed/react documentation](https://www.npmjs.com/package/@filefeed/react)
## Quick Links
Custom transforms, validations, and advanced options
## Example Projects
Complete React application with FileFeed embedding - ready to run example
# Welcome to FileFeed
Source: https://docs.filefeed.io/index
Powerful file import and processing platform for modern applications
## What is FileFeed?
FileFeed is a comprehensive platform that simplifies file import and processing for modern applications. Whether you need to embed file importers directly into your React applications or set up automated file processing workflows, FileFeed provides the tools you need.
Start building with FileFeed in minutes.
## Key Features
Integrate file import functionality directly into your React applications with our easy-to-use SDK.
Set up automated file processing workflows with SFTP and other integrations.
## Quick Navigation
Learn how to integrate FileFeed into your React applications.
Set up automated file processing with SFTP integration.
TypeScript SDK for programmatic access to FileFeed.
# MCP Server
Source: https://docs.filefeed.io/mcp-server/overview
Use FileFeed with AI assistants via the Model Context Protocol
## Overview
The `@filefeed/mcp-server` package exposes all FileFeed SDK capabilities as **MCP (Model Context Protocol) tools**, enabling AI assistants to manage your pipelines, clients, schemas, webhooks, and data directly.
Chat with your FileFeed data in Claude Desktop.
Manage pipelines from your IDE with Cursor.
Use FileFeed tools in VS Code Copilot Chat.
## What is MCP?
The [Model Context Protocol](https://modelcontextprotocol.io) is an open standard that lets AI assistants call external tools. The FileFeed MCP server translates your natural language requests into FileFeed API calls — listing runs, creating pipelines, reprocessing files, and more.
## Quick Start
### 1. Get your API key
Retrieve your API key from the FileFeed dashboard under **Profile > API Key**.
### 2. Configure your AI client
Add to your `claude_desktop_config.json`:
```json theme={null}
{
"mcpServers": {
"filefeed": {
"command": "npx",
"args": ["@filefeed/mcp-server"],
"env": {
"FILEFEED_API_KEY": "your-api-key"
}
}
}
}
```
Add to your Cursor MCP settings (`.cursor/mcp.json`):
```json theme={null}
{
"mcpServers": {
"filefeed": {
"command": "npx",
"args": ["@filefeed/mcp-server"],
"env": {
"FILEFEED_API_KEY": "your-api-key"
}
}
}
}
```
Add to your VS Code settings (`.vscode/settings.json`):
```json theme={null}
{
"mcp": {
"servers": {
"filefeed": {
"command": "npx",
"args": ["@filefeed/mcp-server"],
"env": {
"FILEFEED_API_KEY": "your-api-key"
}
}
}
}
}
```
### 3. Start asking questions
Once configured, you can ask your AI assistant things like:
* *"Show me all failed pipeline runs"*
* *"List my clients and their connection status"*
* *"Create a new pipeline for client Acme with the Employees schema"*
* *"Reprocess the last failed run"*
* *"What webhooks are configured?"*
## Configuration
| Environment Variable | Required | Default | Description |
| --------------------- | -------- | ------------------------- | ------------------------------- |
| `FILEFEED_API_KEY` | Yes | — | Your FileFeed API key |
| `FILEFEED_BASE_URL` | No | `https://api.sftpsync.io` | API base URL |
| `FILEFEED_TIMEOUT_MS` | No | `30000` | Request timeout in milliseconds |
You can also pass the API key via CLI flag:
```bash theme={null}
filefeed-mcp --api-key your-api-key
```
## Next steps
See all 38 tools organized by resource.
Use the TypeScript SDK for programmatic access.
# Available Tools
Source: https://docs.filefeed.io/mcp-server/tools
Complete reference of all 38 MCP tools
## Tool Reference
The FileFeed MCP server exposes **38 tools** across 6 resource groups. Each tool includes proper MCP annotations (`readOnlyHint`, `destructiveHint`, `idempotentHint`) so AI clients can make informed decisions about tool safety.
All tools use `registerTool()` (the current MCP SDK API) with `title`, `description`, `inputSchema`, and `annotations`.
## Clients
Manage SFTP clients and their connection details.
| Tool | Annotations | Description |
| ------------------------- | :---------: | -------------------------------------- |
| `clients_list` | read-only | List all SFTP clients in the workspace |
| `clients_retrieve` | read-only | Get a single client by ID |
| `clients_create` | — | Create a new SFTP client |
| `clients_update` | idempotent | Update an existing client |
| `clients_remove` | destructive | Delete a client |
| `clients_test_connection` | read-only | Test SFTP connectivity for a client |
**Example prompt:** *"Test the connection for my Acme client"*
## Schemas
Define and validate your target data model.
| Tool | Annotations | Description |
| ------------------ | :---------: | ------------------------------------------ |
| `schemas_list` | read-only | List all data schemas |
| `schemas_retrieve` | read-only | Get a single schema by ID |
| `schemas_create` | — | Create a new schema with field definitions |
| `schemas_update` | idempotent | Update an existing schema |
| `schemas_remove` | destructive | Delete a schema |
| `schemas_validate` | read-only | Validate data against a schema |
**Example prompt:** *"Show me the fields in my Employees schema"*
## Pipelines
Connect clients to schemas and define how files are transformed.
| Tool | Annotations | Description |
| ------------------------- | :---------: | ----------------------------------------- |
| `pipelines_list` | read-only | List all pipelines (filterable by client) |
| `pipelines_retrieve` | read-only | Get a single pipeline with full config |
| `pipelines_create` | — | Create a new pipeline with field mappings |
| `pipelines_update` | idempotent | Update an existing pipeline |
| `pipelines_remove` | destructive | Delete a pipeline |
| `pipelines_toggle_active` | — | Toggle pipeline active/inactive status |
**Example prompt:** *"Create a pipeline connecting client Acme to the Employees schema with these field mappings..."*
Field mappings can be sourced (`{ source, target }`) or static (`{ target, value }` — a fixed constant written into a column on every row, e.g. *"...and set `source_system` to `FileFeed` on every row"*).
## Pipeline Runs
Track file processing executions and access processed data.
| Tool | Annotations | Description |
| --------------------------------- | :---------: | --------------------------------------------------- |
| `pipeline_runs_list` | read-only | List runs with filtering (status, client, pipeline) |
| `pipeline_runs_retrieve` | read-only | Get a single run by ID |
| `pipeline_runs_get_data` | read-only | Get processed data from a run (paginated) |
| `pipeline_runs_ack` | idempotent | Acknowledge a run as consumed |
| `pipeline_runs_reprocess` | — | Reprocess a failed run |
| `pipeline_runs_get_original_url` | read-only | Get presigned URL for original file |
| `pipeline_runs_get_processed_url` | read-only | Get presigned URL for processed file |
| `pipeline_runs_get_by_pipeline` | read-only | List runs for a specific pipeline |
**Example prompt:** *"Show me all failed runs from the last week and reprocess them"*
## Webhooks
Receive signed HTTP notifications for pipeline events.
| Tool | Annotations | Description |
| -------------------------- | :---------: | ------------------------------ |
| `webhooks_list` | read-only | List all webhooks |
| `webhooks_retrieve` | read-only | Get a single webhook by ID |
| `webhooks_create` | — | Create a new webhook |
| `webhooks_update` | idempotent | Update an existing webhook |
| `webhooks_remove` | destructive | Delete a webhook |
| `webhooks_list_deliveries` | read-only | List webhook delivery attempts |
**Example prompt:** *"Show me recent failed webhook deliveries"*
## Outbound
Push JSON data into outbound pipelines.
| Tool | Annotations | Description |
| ---------------------------- | :---------: | -------------------------------------------------- |
| `outbound_init_upload` | — | Initialize a multipart upload session |
| `outbound_upload_part` | — | Upload a data chunk |
| `outbound_complete_upload` | — | Complete and trigger processing |
| `outbound_abort_upload` | destructive | Abort an upload session |
| `outbound_get_upload_status` | read-only | Check upload progress |
| `outbound_upload_json` | — | Upload JSON data (auto-chunked convenience method) |
**Example prompt:** *"Upload this JSON data to my outbound pipeline for client Acme"*
## Tool Annotations
MCP tool annotations help AI clients understand tool behavior:
| Annotation | Meaning |
| --------------- | --------------------------------------------------------------------------------------- |
| **read-only** | Tool only reads data, no side effects. Safe to call freely. |
| **idempotent** | Calling the tool multiple times with the same input produces the same result. |
| **destructive** | Tool permanently deletes or aborts resources. AI clients should confirm before calling. |
| **—** | Tool has side effects (creates/modifies data) but is not destructive. |
# Upgrade to 2026-05-25
Source: https://docs.filefeed.io/migration/v1-to-v2
Rename Client to Connection across the API and SDK
API version `2026-05-25` renames the **Client** entity to **Connection**.
That's the entire change — the wire format, request bodies, response shapes,
and IDs are all identical to `2024-09-01`. The legacy `/clients` endpoints
and the SDK's `filefeed.clients.*` namespace continue to work for **12
months**, until `2024-09-01` is sunset on **2027-05-25**.
**No action is required today.** Existing integrations keep working until
the sunset date. This guide is here when you're ready to switch.
## At a glance
| Before (`2024-09-01`) | After (`2026-05-25`) |
| ------------------------------------- | --------------------------------------- |
| `GET /clients` | `GET /connections` |
| `GET /clients/:id` | `GET /connections/:id` |
| `POST /clients` | `POST /connections` |
| `PATCH /clients/:id` | `PATCH /connections/:id` |
| `DELETE /clients/:id` | `DELETE /connections/:id` |
| `POST /clients/:id/test-connection` | `POST /connections/:id/test-connection` |
| `filefeed.clients.*` (SDK) | `filefeed.connections.*` (SDK) |
| `filefeed.clients.testConnection(id)` | `filefeed.connections.test(id)` |
| `Client`, `CreateClientParams` types | `Connection`, `CreateConnectionParams` |
The fields inside `Connection` are byte-for-byte identical to v1's `Client` —
you don't need to touch request bodies, only the URL path and the resource
name.
## Backward-compat guarantee
Both the API and the SDK serve the legacy names alongside the canonical ones:
* `/clients/*` HTTP routes still work and return identical JSON.
* `filefeed.clients.*` SDK methods still work and proxy to `connections.*`.
* `Client`, `CreateClientParams`, `UpdateClientParams` TypeScript types are
aliases for the new names — your existing types still compile.
The legacy surfaces emit deprecation signals so you know which call sites
still need to be updated:
* HTTP responses include `Deprecation: true`, `Sunset: 2027-05-25`, and a
`Link` header pointing to this guide.
* The SDK's `onDeprecation` callback fires once per deprecated method per
process. Falls back to `console.warn` if no callback is configured.
## Step 1 — Pin to the new version
Send the version header on every request:
```http theme={null}
GET /connections HTTP/1.1
Host: api.sftpsync.io
X-API-Key: sk_live_...
FileFeed-Version: 2026-05-25
```
Or set the default for your entire workspace in the dashboard
(**Settings → API → Default version**). All requests that don't supply a
header will adopt that default.
If you use the SDK, **upgrade to `@filefeed/sdk@2`** — it pins the header
automatically:
```bash theme={null}
npm install @filefeed/sdk@2
```
```ts theme={null}
import { FileFeed } from '@filefeed/sdk';
const filefeed = new FileFeed({
apiKey: process.env.FILEFEED_API_KEY!,
// Optional — explicit pinning. Defaults to the SDK's release version.
apiVersion: '2026-05-25',
// Surface deprecation signals to your error tracker.
onDeprecation: (warning) => {
Sentry.captureMessage(warning.message, 'warning');
},
});
```
## Step 2 — Find your call sites
Grep your codebase for the legacy names:
```bash theme={null}
# HTTP callers
rg "/clients\b" src/
rg "X-API-Key:.*clients" src/
# SDK callers
rg "filefeed\.clients\." src/
rg "CreateClientParams|UpdateClientParams|: Client[^a-zA-Z]" src/
```
## Step 3 — Rename mechanically
Each call site is a one-line edit. Bodies and field names are unchanged.
```ts SDK theme={null}
- const c = await filefeed.clients.retrieve(id);
+ const c = await filefeed.connections.retrieve(id);
- await filefeed.clients.testConnection(id);
+ await filefeed.connections.test(id);
```
```bash curl theme={null}
- curl https://api.sftpsync.io/clients \
+ curl https://api.sftpsync.io/connections \
-H 'X-API-Key: sk_live_...' \
+ -H 'FileFeed-Version: 2026-05-25' \
-H 'Content-Type: application/json' \
-d '{
"name": "Acme :: Production",
"useHostedSFTP": true,
"awsPassword": "strong-password"
}'
```
```ts Types theme={null}
- import type { Client, CreateClientParams } from '@filefeed/sdk';
+ import type { Connection, CreateConnectionParams } from '@filefeed/sdk';
- function syncClient(c: Client) { ... }
+ function syncConnection(c: Connection) { ... }
```
## Step 4 — Watch for deprecation signals
Until your cutover is complete, configure the SDK callback so the legacy
calls don't go unnoticed:
```ts theme={null}
new FileFeed({
apiKey: process.env.FILEFEED_API_KEY!,
onDeprecation: (w) => {
console.warn(`[FileFeed] ${w.method ?? w.source}: ${w.message}`);
Sentry.captureMessage(w.message, 'warning');
},
});
```
Or if you're calling the HTTP API directly, log responses that carry
`Deprecation: true`:
```ts theme={null}
if (response.headers.get('deprecation') === 'true') {
logger.warn('Deprecated FileFeed route', {
url: response.url,
sunset: response.headers.get('sunset'),
link: response.headers.get('link'),
});
}
```
## FAQ
**Do my Pipelines or Pipeline Runs need re-creation?**
No. Pipelines continue to reference the same underlying records — they're
linked by ID, and the IDs are unchanged. The Connection resource is the
same database row, just under a new name.
**Will `clientId` fields in Pipeline payloads keep working?**
Yes. Pipeline request/response payloads still expose `clientId` on
`2026-05-25` for backward compatibility. We may add a `connectionId` alias
in a later version, but `clientId` will keep working until the next major
versioned change.
**Why ship a version for a rename?**
So that you control the cutover. Without a versioned change, the SDK would
have had to either break compile-time types on upgrade or silently keep
both names forever. The versioned path lets the rename feel cosmetic to
existing customers while letting new customers see the canonical name from
day one.
**What if I do nothing?**
Your integration keeps working. Around 30 days before the sunset date you'll
get email warnings; if your traffic on `2024-09-01` is still significant
we'll reach out directly to coordinate the cutover.
## Related
* [Changelog](/changelog) — full version history
* [API Introduction](/api-reference/introduction) — versioning headers
* [SDK migration guide](https://github.com/filefeed/filefeed-sdk/blob/main/MIGRATION.md) — SDK-specific code diffs
# Quick Start
Source: https://docs.filefeed.io/quickstart
Get up and running with FileFeed in minutes
## Get started with FileFeed
Follow these simple steps to integrate FileFeed into your application.
### Step 1: Create your account
Create your FileFeed account to get started with our platform.
1. Visit our [dashboard](https://filefeed.io/signup)
2. Sign up with your **company email** — registration requires a work email
address; public providers (gmail.com, outlook.com, etc.) are rejected.
Once you’re logged in, go to My Account → Security Settings, then click Reveal API Key to view your API key.
Keep your API key secure and never commit it to version control.
### Step 2: Choose your integration method
For React applications, use our React SDK to embed file import functionality directly into your app.
Learn how to integrate FileFeed into your React applications.
Set up automated file processing workflows with SFTP and other integrations.
Set up automated file processing with SFTP integration.
### Step 3: Test your integration
1. Follow the integration guide for your chosen method
2. Test file uploads and processing
3. Check your dashboard for processed files
## Next steps
Now that you have FileFeed set up, explore these features:
Learn about our embedded file import solutions.
Integrate FileFeed into your React applications.
Set up automated file processing workflows.
Configure SFTP-based file processing.
TypeScript SDK for programmatic access.
**Need help?** Contact our [support team](mailto:support@filefeed.io) or check out our detailed guides.