diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1db625544..0b33500a7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,7 @@
### Enhancements
+* **Migrate Notion Source Connector to V2**
* **Migrate Vectara Destination Connector to v2**
* **Added Redis destination connector**
* **Improved Milvus error handling**
diff --git a/test/integration/connectors/expected_results/notion_database/directory_structure.json b/test/integration/connectors/expected_results/notion_database/directory_structure.json
new file mode 100644
index 000000000..9962865c6
--- /dev/null
+++ b/test/integration/connectors/expected_results/notion_database/directory_structure.json
@@ -0,0 +1,5 @@
+{
+ "directory_structure": [
+ "1722c3765a0a8082b382ebc2c62d3f4c.html"
+ ]
+}
\ No newline at end of file
diff --git a/test/integration/connectors/expected_results/notion_database/downloads/1722c3765a0a8082b382ebc2c62d3f4c.html b/test/integration/connectors/expected_results/notion_database/downloads/1722c3765a0a8082b382ebc2c62d3f4c.html
new file mode 100644
index 000000000..dce7fc3a5
--- /dev/null
+++ b/test/integration/connectors/expected_results/notion_database/downloads/1722c3765a0a8082b382ebc2c62d3f4c.html
@@ -0,0 +1,330 @@
+
+
+
+ Author
+ |
+
+ Email
+ |
+
+ Formula
+ |
+
+ ID
+ |
+
+ Item
+ |
+
+ Phone
+ |
+
+ Priority Level
+ |
+
+ Publication Date
+ |
+
+ Status
+ |
+
+ Tag
+ |
+
+ URL
+ |
+
+ Views
+ |
+
+
+
+
+ |
+
+
+ xyz@abc.com
+
+ |
+
+
+ 12
+
+ |
+
+
+ None-4
+
+ |
+
+
+ test-page4-in-database
+
+ |
+
+
+ 1234567890
+
+ |
+
+
+ High
+
+ |
+
+
+ 2025-01-31
+
+ |
+
+
+ Not started
+
+ |
+
+
+
+ V1
+
+
+ V5
+
+
+ V7
+
+
+ |
+
+
+ https://abcde.com
+
+ |
+
+
+ 6
+
+ |
+
+
+
+
+ |
+
+
+ xyz@abc.com
+
+ |
+
+
+ 90
+
+ |
+
+
+ None-3
+
+ |
+
+
+ test-page3-in-database
+
+ |
+
+
+ 1234567890
+
+ |
+
+
+ Medium
+
+ |
+
+
+ 2025-01-06
+
+ |
+
+
+ In Review
+
+ |
+
+
+
+ V5
+
+
+ V6
+
+
+ |
+
+
+ https://abcde.com
+
+ |
+
+
+ 45
+
+ |
+
+
+
+
+ |
+
+
+ xyz@abc.com
+
+ |
+
+
+ 46
+
+ |
+
+
+ None-2
+
+ |
+
+
+ test-page2-in-database
+
+ |
+
+
+ 1234567890
+
+ |
+
+
+ Low
+
+ |
+
+
+ 2025-01-04
+
+ |
+
+
+ Done
+
+ |
+
+
+
+ V1
+
+
+ V2
+
+
+ V4
+
+
+ |
+
+
+ https://abcde.com
+
+ |
+
+
+ 23
+
+ |
+
+
+
+
+ |
+
+
+ xyz@abc.com
+
+ |
+
+
+ 4
+
+ |
+
+
+ None-1
+
+ |
+
+
+ test-page1-in-datab
+
+ |
+
+
+ 1234567890
+
+ |
+
+
+ High
+
+ |
+
+
+ 2024-12-01
+
+ |
+
+
+ In progress
+
+ |
+
+
+
+ V1
+
+
+ V3
+
+
+ |
+
+
+ https://abcde.com
+
+ |
+
+
+ 2
+
+ |
+
+
diff --git a/test/integration/connectors/expected_results/notion_database/file_data/1722c3765a0a8082b382ebc2c62d3f4c.json b/test/integration/connectors/expected_results/notion_database/file_data/1722c3765a0a8082b382ebc2c62d3f4c.json
new file mode 100644
index 000000000..a49fbf0f2
--- /dev/null
+++ b/test/integration/connectors/expected_results/notion_database/file_data/1722c3765a0a8082b382ebc2c62d3f4c.json
@@ -0,0 +1,39 @@
+{
+ "identifier": "1722c3765a0a8082b382ebc2c62d3f4c",
+ "connector_type": "notion",
+ "source_identifiers": {
+ "filename": "1722c3765a0a8082b382ebc2c62d3f4c.html",
+ "fullpath": "1722c3765a0a8082b382ebc2c62d3f4c.html",
+ "rel_path": "1722c3765a0a8082b382ebc2c62d3f4c.html"
+ },
+ "metadata": {
+ "url": null,
+ "version": null,
+ "record_locator": {
+ "database_id": "1722c3765a0a8082b382ebc2c62d3f4c"
+ },
+ "date_created": "2025-01-05T18:34:00.000Z",
+ "date_modified": "2025-01-07T19:15:00.000Z",
+ "date_processed": "1736277913.3980532",
+ "permissions_data": null,
+ "filesize_bytes": null
+ },
+ "additional_metadata": {
+ "created_by": {
+ "id": "118d872b-594c-8171-b46f-00020d10d8b2",
+ "object": "user"
+ },
+ "last_edited_by": {
+ "id": "118d872b-594c-8171-b46f-00020d10d8b2",
+ "object": "user"
+ },
+ "parent": {
+ "type": "workspace",
+ "workspace": true
+ },
+ "url": "https://www.notion.so/1722c3765a0a8082b382ebc2c62d3f4c"
+ },
+ "reprocess": false,
+ "local_download_path": "/private/var/folders/h7/n848df9s5yn7ml8rxb61vhyc0000gp/T/tmpxu906ary/1722c3765a0a8082b382ebc2c62d3f4c.html",
+ "display_name": null
+}
\ No newline at end of file
diff --git a/test/integration/connectors/expected_results/notion_page/directory_structure.json b/test/integration/connectors/expected_results/notion_page/directory_structure.json
new file mode 100644
index 000000000..9d7654273
--- /dev/null
+++ b/test/integration/connectors/expected_results/notion_page/directory_structure.json
@@ -0,0 +1,5 @@
+{
+ "directory_structure": [
+ "1572c3765a0a806299f0dd6999f9e4c7.html"
+ ]
+}
\ No newline at end of file
diff --git a/test/integration/connectors/expected_results/notion_page/downloads/1572c3765a0a806299f0dd6999f9e4c7.html b/test/integration/connectors/expected_results/notion_page/downloads/1572c3765a0a806299f0dd6999f9e4c7.html
new file mode 100644
index 000000000..6d816a0e7
--- /dev/null
+++ b/test/integration/connectors/expected_results/notion_page/downloads/1572c3765a0a806299f0dd6999f9e4c7.html
@@ -0,0 +1,244 @@
+
+
+
+
+
+ testtext2 testtext2 testtext2 testtext2 testtext2 testtext2 testtext2 testtext2 testtext2 testtext2
+
+
+ testtext2 testtext2 testtext2 testtext2 testtext2 testtext2 testtext2 testtext2 testtext2 testtext2
+
+

+
+
+ -
+ Testdoc2 List Item 1
+
+
+
+ -
+ Testdoc2 List Item 1 Nested Item A
+
+ -
+ Testdoc2 List Item 1 Nested Item B
+
+
+
+
+ -
+ Testdoc2 List Item 2
+
+ -
+ Testdoc2 List Item 3
+
+
+
+
+
+
+
+
+ Testdoc2 Checklist Item 1
+
+
+
+
+
+
+ Testdoc2 Checklist Item 2 (checked)
+
+
+
+
+

+

+
+
+ Testdoc2 bold text
+
+
+
+
+ Testdoc2 italic text
+
+
+
+
+ Testdoc2 Heading 1 Sized Text
+
+
+
+
+ Testdoc2 Heading 2 Sized Text
+
+
+
+
+ Table
+
+
+
+
+
+ Testdoc2 Table: Column 1 Row 0
+
+ |
+
+
+ Testdoc2 Table: Column 2 Row 0
+
+ |
+
+
+ Testdoc2 Table: Column 3 Row 0
+
+ |
+
+
+
+
+ Testdoc2 Table: Column 1 Row 1
+
+ |
+
+
+ Testdoc2 Table: Column 2 Row 1
+
+ |
+
+
+ Testdoc2 Table: Column 3 Row 1
+
+ |
+
+
+
+
+ Testdoc2 Table: Column 1 Row 2
+
+ |
+
+
+ Testdoc2 Table: Column 2 Row 2
+
+ |
+
+
+ Testdoc2 Table: Column 3 Row 2
+
+ |
+
+
+

+
+ 2 Columns in ColumnList
+
+
+
+
+ -
+ Item 1
+
+ -
+ Item 2
+
+
+
+ Expandable Heading
+
+
+ -
+ First child item
+
+ -
+ Second child item
+
+
+
+
+ -
+ First item in Numbered list
+
+ -
+ Second item in Numbered list
+
+
+
+
+
+
+ -
+ Expandable Section
+
+
+
+ -
+ Child item 1
+
+ -
+ Child item 2
+
+
+
+
+
+ Column list with indented items
+
+
+
+
+ -
+ Second level item
+
+
+
+
+
+
+
+
+ 💡
+
+ this is a Callout block
+
+
+ this is a Quote block
+
+
+
+
+
+ this is a Code block
+
+
+
+
+ this()is()a()block()equation.
+
+
+
+
+
diff --git a/test/integration/connectors/expected_results/notion_page/file_data/1572c3765a0a806299f0dd6999f9e4c7.json b/test/integration/connectors/expected_results/notion_page/file_data/1572c3765a0a806299f0dd6999f9e4c7.json
new file mode 100644
index 000000000..88e9b69dc
--- /dev/null
+++ b/test/integration/connectors/expected_results/notion_page/file_data/1572c3765a0a806299f0dd6999f9e4c7.json
@@ -0,0 +1,39 @@
+{
+ "identifier": "1572c3765a0a806299f0dd6999f9e4c7",
+ "connector_type": "notion",
+ "source_identifiers": {
+ "filename": "1572c3765a0a806299f0dd6999f9e4c7.html",
+ "fullpath": "1572c3765a0a806299f0dd6999f9e4c7.html",
+ "rel_path": "1572c3765a0a806299f0dd6999f9e4c7.html"
+ },
+ "metadata": {
+ "url": null,
+ "version": null,
+ "record_locator": {
+ "page_id": "1572c3765a0a806299f0dd6999f9e4c7"
+ },
+ "date_created": "2024-12-09T18:13:00.000Z",
+ "date_modified": "2025-01-07T19:24:00.000Z",
+ "date_processed": "1736277919.434568",
+ "permissions_data": null,
+ "filesize_bytes": null
+ },
+ "additional_metadata": {
+ "created_by": {
+ "id": "118d872b-594c-8171-b46f-00020d10d8b2",
+ "object": "user"
+ },
+ "last_edited_by": {
+ "id": "118d872b-594c-8171-b46f-00020d10d8b2",
+ "object": "user"
+ },
+ "parent": {
+ "page_id": "1182c376-5a0a-8042-9a2a-fb003e00d57b",
+ "type": "page_id"
+ },
+ "url": "https://www.notion.so/test-doc1-1572c3765a0a806299f0dd6999f9e4c7"
+ },
+ "reprocess": false,
+ "local_download_path": "/private/var/folders/h7/n848df9s5yn7ml8rxb61vhyc0000gp/T/tmpluf__jry/1572c3765a0a806299f0dd6999f9e4c7.html",
+ "display_name": null
+}
\ No newline at end of file
diff --git a/test/integration/connectors/test_notion.py b/test/integration/connectors/test_notion.py
new file mode 100644
index 000000000..aabc5cf5c
--- /dev/null
+++ b/test/integration/connectors/test_notion.py
@@ -0,0 +1,145 @@
+import os
+
+from test.integration.connectors.utils.validation.source import (
+ SourceValidationConfigs,
+ get_all_file_data,
+ run_all_validations,
+ update_fixtures,
+)
+from unstructured_ingest.v2.interfaces import Downloader, Indexer
+from unstructured_ingest.v2.processes.connectors.notion.connector import (
+ NotionAccessConfig,
+ NotionConnectionConfig,
+ NotionDownloader,
+ NotionDownloaderConfig,
+ NotionIndexer,
+ NotionIndexerConfig,
+)
+
+
+def test_notion_source_database(temp_dir):
+ # Retrieve environment variables
+ notion_api_key = os.environ["NOTION_API_KEY"]
+
+ # Create connection and indexer configurations
+ access_config = NotionAccessConfig(notion_api_key=notion_api_key)
+ connection_config = NotionConnectionConfig(
+ access_config=access_config,
+ )
+ index_config = NotionIndexerConfig(
+ database_ids=["1722c3765a0a8082b382ebc2c62d3f4c"], recursive=False
+ )
+
+ download_config = NotionDownloaderConfig(download_dir=temp_dir)
+
+ # Instantiate indexer and downloader
+ indexer = NotionIndexer(
+ connection_config=connection_config,
+ index_config=index_config,
+ )
+ downloader = NotionDownloader(
+ connection_config=connection_config,
+ download_config=download_config,
+ )
+
+ # Run the source connector validation
+ source_connector_validation(
+ indexer=indexer,
+ downloader=downloader,
+ configs=SourceValidationConfigs(
+ test_id="notion_database",
+ expected_num_files=1,
+ validate_downloaded_files=True,
+ exclude_fields_extend=["metadata.date_created", "metadata.date_modified"],
+ ),
+ )
+
+
+def test_notion_source_page(temp_dir):
+ # Retrieve environment variables
+ notion_api_key = os.environ["NOTION_API_KEY"]
+
+ # Create connection and indexer configurations
+ access_config = NotionAccessConfig(notion_api_key=notion_api_key)
+ connection_config = NotionConnectionConfig(
+ access_config=access_config,
+ )
+ index_config = NotionIndexerConfig(
+ page_ids=["1572c3765a0a806299f0dd6999f9e4c7"], recursive=False
+ )
+
+ download_config = NotionDownloaderConfig(download_dir=temp_dir)
+
+ # Instantiate indexer and downloader
+ indexer = NotionIndexer(
+ connection_config=connection_config,
+ index_config=index_config,
+ )
+ downloader = NotionDownloader(
+ connection_config=connection_config,
+ download_config=download_config,
+ )
+
+ # Run the source connector validation
+ source_connector_validation(
+ indexer=indexer,
+ downloader=downloader,
+ configs=SourceValidationConfigs(
+ test_id="notion_page",
+ expected_num_files=1,
+ validate_downloaded_files=True,
+ exclude_fields_extend=["metadata.date_created", "metadata.date_modified"],
+ ),
+ )
+
+
+def source_connector_validation(
+ indexer: Indexer,
+ downloader: Downloader,
+ configs: SourceValidationConfigs,
+ overwrite_fixtures: bool = os.getenv("OVERWRITE_FIXTURES", "False").lower() == "true",
+) -> None:
+ # Run common validations on the process of running a source connector, supporting dynamic
+ # validators that get passed in along with comparisons on the saved expected values.
+ # If overwrite_fixtures is st to True, will ignore all validators but instead overwrite the
+ # expected values with what gets generated by this test.
+ all_predownload_file_data = []
+ all_postdownload_file_data = []
+ indexer.precheck()
+ download_dir = downloader.download_config.download_dir
+ test_output_dir = configs.test_output_dir()
+
+ for file_data in indexer.run():
+ assert file_data
+ predownload_file_data = file_data.model_copy(deep=True)
+ all_predownload_file_data.append(predownload_file_data)
+ resp = downloader.run(file_data=file_data)
+ if isinstance(resp, list):
+ for r in resp:
+ postdownload_file_data = r["file_data"].model_copy(deep=True)
+ all_postdownload_file_data.append(postdownload_file_data)
+ else:
+ postdownload_file_data = resp["file_data"].model_copy(deep=True)
+ all_postdownload_file_data.append(postdownload_file_data)
+
+ if not overwrite_fixtures:
+ print("Running validation")
+ run_all_validations(
+ configs=configs,
+ predownload_file_data=all_predownload_file_data,
+ postdownload_file_data=all_postdownload_file_data,
+ download_dir=download_dir,
+ test_output_dir=test_output_dir,
+ )
+ else:
+ print("Running fixtures update")
+ update_fixtures(
+ output_dir=test_output_dir,
+ download_dir=download_dir,
+ all_file_data=get_all_file_data(
+ all_predownload_file_data=all_predownload_file_data,
+ all_postdownload_file_data=all_postdownload_file_data,
+ ),
+ save_downloads=configs.validate_downloaded_files,
+ save_filedata=configs.validate_file_data,
+ )
diff --git a/test_e2e/expected-structured-output/notion/122b2c22-996b-435b-9de2-ee0e9d2b04bc.json b/test_e2e/expected-structured-output/notion/122b2c22-996b-435b-9de2-ee0e9d2b04bc.json
deleted file mode 100644
index a53e41bfc..000000000
--- a/test_e2e/expected-structured-output/notion/122b2c22-996b-435b-9de2-ee0e9d2b04bc.json
+++ /dev/null
@@ -1,14 +0,0 @@
-[
- {
- "element_id": "59a715faf8dcf15a6855a2c070f5d4cd",
- "metadata": {
- "filetype": "text/html",
- "languages": [
- "eng"
- ],
- "text_as_html": "