---
title: "Create a feed"
method: POST
path: "/v1/feeds"
tags: ["Feeds"]
---

# Create a feed

`POST /v1/feeds`

## Request

- Base URL: `https://api.banksync.io`
- URL: `https://api.banksync.io/v1/feeds`
- Auth: one of:
  - API key in header `X-API-Key`
  - HTTP bearer

## Request body

- object
  - `name` string, required: Human-readable feed name, e.g. "ANZ Transactions → Notion"
  - `source` 'sync' | 'extractor' | 'upload', required: "sync" = bank API; "extractor" = email/PDF AI extraction; "upload" = file upload
  - `dataType` 'transactions' | 'balances' | 'trades' | 'holdings' | 'orders' | 'loans' | 'receipts' | 'invoices' | 'documents', required: Type of financial data this feed produces
  - `icon` string: Optional emoji or icon identifier
  - `order` integer: Display sort order
  - `sourceConfig` union: How to connect to the data source. Required before triggering a sync.
    - object: Bank API sync source — pulls structured financial data from Plaid, SaltEdge, or SnapTrade
      - `type` 'sync', required
      - `accounts` object[], required: One or more bank accounts to sync from
        - `bankId` string, required: Bank ID — get from list_banks
        - `accountId` string, required: Account ID — get from list_accounts
    - object: Email extraction source — processes forwarded emails using AI
      - `type` 'extractor', required
      - `inboxAddress` string, email: Auto-generated forwarding email address (set by system on creation)
      - `whitelistEnabled` boolean: When true, only emails from addresses in the whitelist are processed
      - `whitelist` string[]: Allowed sender email addresses (only used when whitelistEnabled is true)
    - object: File upload source — processes uploaded PDFs/images using AI
      - `type` 'upload', required
  - `destinationConfig` union: Where to write the data. Required before triggering a sync.
    - object: Write to a Notion database
      - `type` 'notion', required
      - `integrationId` string, required: Notion integration ID — get from list_integrations
      - `databaseId` string, required: Notion database ID to write records into
    - object: Write to an Airtable table
      - `type` 'airtable', required
      - `integrationId` string, required: Airtable integration ID — get from list_integrations
      - `baseId` string, required: Airtable base ID
      - `tableId` string, required: Airtable table ID to write records into
    - object: Write to a Google Sheets spreadsheet
      - `type` 'google_sheets', required
      - `integrationId` string, required: Google Sheets integration ID — get from list_integrations
      - `spreadsheetId` string, required: Google Sheets spreadsheet ID
      - `sheetName` string, required: Name of the sheet tab to write into
      - `attachmentFolderId` string: Optional Google Drive folder ID for storing file attachments
      - `direction` 'row' | 'column', required: "row" = each record is a row (default); "column" = each record is a column
      - `headerRowOrColumn` integer, required: Row number (for row direction) or column number (for column direction) that contains headers
      - `pushLocation` 'beginning' | 'end', required: Where to insert new records: "beginning" prepends, "end" appends
    - object: Write to a Microsoft Excel workbook on OneDrive
      - `type` 'excel', required
      - `integrationId` string, required: Excel integration ID — get from list_integrations
      - `driveId` string, required: OneDrive drive ID (get from getWorkspaces)
      - `workbookId` string, required: Excel workbook item ID (get from searchDatabases)
      - `worksheetName` string, required: Name of the worksheet tab to write into
      - `attachmentFolderId` string: Optional OneDrive folder ID for storing file attachments
      - `attachmentDriveId` string: Drive ID for the attachment folder (defaults to workbook driveId)
      - `preferTablesApi` boolean: Prefer Excel Tables API when target is inside an Excel Table (org accounts only)
      - `direction` 'row' | 'column', required: "row" = each record is a row (default); "column" = each record is a column
      - `headerRowOrColumn` integer, required: Row number (for row direction) or column number (for column direction) that contains headers
      - `pushLocation` 'beginning' | 'end', required: Where to insert new records: "beginning" prepends, "end" appends
    - object: Write to a customer SQL database through the database gateway
      - `type` 'database', required
      - `integrationId` string, required: Database integration ID — get from list_integrations
      - `schema` string: Postgres schema / MySQL database. Optional; gateway resolves a default.
      - `table` string, required: Target table (SQL) / collection (document)
      - `dedupKeys` string[]: Destination column names forming the unique key for upsert. Empty => append-only.
      - `writeMode` 'append' | 'upsert', required: "upsert" dedupes on dedupKeys; "append" is append-only
    - object: POST signed JSON to a customer HTTPS endpoint. No field mapping: the payload is the standard versioned envelope (see the webhooks developer docs). Supports transactions, balances, holdings, trades, orders, and loans.
      - `type` 'webhook', required
      - `integrationId` string, required: Webhook endpoint integration ID — get from list_integrations
    - object: Store rows in a BankSync table inside this workspace. No connection setup and no field mapping required.
      - `type` 'table', required
      - `tableId` string, required: BankSync table ID — get from list_tables
      - `writeMode` 'upsert' | 'append': upsert (default): re-syncing an updated record replaces its row. append: every sync writes new rows, keeping a full history.
    - object: Deliver signed JSON to an installed app. No field mapping: the payload is the standard versioned envelope plus the app header block. Supports transactions, balances, holdings, trades, orders, and loans.
      - `type` 'app', required
      - `integrationId` string, required: Installed-app integration ID — get from list_integrations
    - object: Send posted transactions into a YNAB plan. No field mapping: each bank account maps to a YNAB account. Set up in the BankSync app only.
      - `type` 'ynab', required
      - `integrationId` string, required: YNAB connection integration ID — get from list_integrations
      - `planId` string, required: YNAB plan ID
      - `accountMap` object[], required: One entry per source bank account: its YNAB account, or "skip"
        - `bankId` string, required
        - `accountId` string, required
        - `bankWorkspaceId` string
        - `ynabAccountId` string, nullable, required
        - `mode` 'send' | 'skip', required
        - `cutoffDate` string, date, required
        - `createdByBankSync` boolean, required
        - `startingBalance` object
          - `state` 'pending' | 'posted' | 'not_applicable', required
          - `importId` string
          - `balanceUnknown` boolean
  - `fieldMappings` object[]: Maps source fields to destination columns/properties
    - `sourceField` string, required: Source field key — get valid keys from get_data_type_schema
    - `destinationField` string, required: Destination property ID (Notion/Airtable) or column name (Sheets)
  - `dataTypeOptions` union: Data-type-specific processing options (sync feeds only)
    - object: Processing options for transaction feeds
      - `dataType` 'transactions', required
      - `pendingMode` 'sync_all' | 'filter_pending' | 'track_and_update', required: "sync_all" — include pending transactions; a pending transaction and its settled version arrive as separate rows. "filter_pending" — only settled transactions. "track_and_update" — not yet available; rejected on write.
    - object: Processing options for balance feeds
      - `dataType` 'balances', required
      - `mode` 'append' | 'overwrite', required: "append" — add a new row for each sync (historical log); "overwrite" — replace the existing record (live snapshot)
    - object: Processing options for trade feeds
      - `dataType` 'trades', required
    - object: Processing options for holdings feeds
      - `dataType` 'holdings', required
    - object: Processing options for order feeds
      - `dataType` 'orders', required
    - object: Processing options for loan feeds
      - `dataType` 'loans', required
  - `transactionSyncOptions` object: Deprecated alias of dataTypeOptions.pendingMode (transaction feeds only)
    - `pendingTransactionMode` 'sync_all' | 'filter_pending' | 'track_and_update': Same values as dataTypeOptions.pendingMode
  - `extractionConfig` object: AI extraction field definitions (extractor/upload feeds only)
    - `extractionFields` object[], required: Fields the AI will extract from each document
      - `key` string, required: Unique field identifier (letters, numbers, underscores)
      - `name` string, required: Field name
      - `type` 'string' | 'number' | 'date' | 'currency' | 'boolean' | 'category' | 'id', required: Field data type
      - `description` string: Description to guide AI extraction
      - `examples` string[]: Example values to improve extraction accuracy
      - `isItemField` boolean: True if this field is part of a line-item list (e.g. individual receipt items)
    - `itemizePerRow` boolean, required: True = one destination row per extracted item; False = one row per document
    - `extractionInstructions` string: Custom instructions for the AI extractor (e.g. "always use AUD for currency")
  - `schedule` object: Automated sync schedule
    - `enabled` boolean, required
    - `frequency` 'hourly' | 'daily' | 'weekly' | 'monthly', required
    - `dayOfWeek` integer: Day of week for weekly schedules (0 = Sunday, 6 = Saturday)
    - `dayOfMonth` integer: Day of month for monthly schedules
    - `timeOfDay` string, required: "HH:MM" UTC format, e.g. "09:30"
  - `notifications` unknown

## Response `201`

Feed created — returns the full feed document

- object
  - `success` true, required
  - `data` object, required
    - `id` string, required
    - `name` string, required
    - `icon` string
    - `workspaceId` string
    - `source` 'sync' | 'extractor' | 'upload', required
    - `dataType` 'transactions' | 'balances' | 'trades' | 'holdings' | 'orders' | 'loans' | 'receipts' | 'invoices' | 'documents', required
    - `sourceConfig` object
    - `destinationConfig` object
    - `fieldMappings` object[]
      - `sourceField` string, required
      - `destinationField` string, required
      - `destinationFieldType` string
    - `dataTypeOptions` object
    - `extractionConfig` object
      - `extractionFields` object[], required
        - `key` string
        - `name` string, required
        - `type` string, required
        - `description` string
        - `examples` string[]
        - `isItemField` boolean
      - `itemizePerRow` boolean, required
      - `extractionInstructions` string
    - `schedule` object
      - `enabled` boolean, required
      - `frequency` 'hourly' | 'daily' | 'weekly' | 'monthly', required
      - `dayOfWeek` integer: Day of week for weekly schedules (0 = Sunday, 6 = Saturday)
      - `dayOfMonth` integer: Day of month for monthly schedules
      - `timeOfDay` string, required: "HH:MM" UTC format, e.g. "09:30"
    - `state` object, required
    - `order` number, required
    - `createdAt` string, required
    - `updatedAt` string, required

## Other responses

- `401`: Unauthorized
- `403`: Forbidden
- `404`: A referenced account is not available to this credential. An access token narrowed to specific accounts (RFC 9396 `banksync_data_access`) cannot source a feed from an account outside that consent, and the response is deliberately identical to the one for an account that does not exist.
- `422`: Validation failed — sourceConfig, fieldMappings, or source×dataType combination is invalid

---

[API](https://skmtc.dev/banksync/apis/banksync-api.md) · [All operations](https://skmtc.dev/banksync/apis/banksync-api/llms.txt) · [OpenAPI document](https://skmtc.dev/banksync/apis/banksync-api/revisions/94465f5ee922?raw)
