feature(meta_lead_ads): add Meta Lead Ads connector example - #69
Open
fivetran-tanishk wants to merge 2 commits into
Open
fivetran-tanishk wants to merge 2 commits into
fivetran-tanishk wants to merge 2 commits into
Conversation
Syncs Facebook (Meta) Lead Ads data into a single leads table using the Graph API, with per-form incremental sync and threshold-based checkpointing. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Match the repo's Code Quality CI check, which runs black with the 99-char line length used across this repo instead of black's default. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
fivetran-rishabhghosh
requested review from
fivetran-ankitsilla,
fivetran-sahilkhirwal and
fivetran-satvikpatil
and removed request for
fivetran-sahilkhirwal
September 18, 2026 13:03
Contributor
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
API failures can silently truncate syncs, and mid-pagination timestamp checkpoints can permanently skip leads.
Get a fresh assessment by requesting another Copilot review.
Review effort: Balanced
Findings: 5
Open (36)
Use a resumable cursor for paginated form sync · New Raise request failures instead of treating them as pagination exhaustion · New Redact URLs and response details from logs · New Use error logging and redact sensitive failure details · New Parse ISO-8601 offsets and reject naive timestamps · New Replace unsupported severe log level with error · New Request name and access_token during discovery · New Request form id, name, and status fields · New Process paginated responses incrementally · New Apply archived filtering only during all-form discovery · New Reject unrecognized boolean configuration values · New Strip access tokens before validation · New Normalize timestamps to canonical UTC during validation · New Add template initialization command to Getting started · New Fix configuration example fence and placeholders · New Document credential setup as ordered user steps · New Use explicit function references in README · New Bold additional filenames while retaining inline code · New Replace literal connector configuration values with placeholders · New Add purpose comments to all imports · New
And 16 more that still need to be addressed.
What changed in this PR
Adds a Meta Lead Ads connector example with Graph API discovery, incremental lead syncing, and checkpointing.
Changes:
- Adds connector logic, API helpers, retries, validation, and configuration.
- Documents setup, authentication, schema, and behavior.
- Registers the connector in the repository catalog.
| File | Description |
|---|---|
README.md |
Adds the connector listing. |
meta_lead_ads/README.md |
Documents the connector. |
meta_lead_ads/configuration.json |
Defines configuration values. |
meta_lead_ads/connector.py |
Implements syncing and checkpointing. |
meta_lead_ads/http_helpers.py |
Implements HTTP retries. |
meta_lead_ads/meta_helpers.py |
Implements Graph API pagination and discovery. |
meta_lead_ads/validator.py |
Validates and normalizes configuration. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Comment on lines
+89
to
+93
| if rows_since_checkpoint >= cfg["check_point_limit"]: | ||
| _write_checkpoint( | ||
| form_id=form_id, | ||
| forms_state=forms_state, | ||
| current_cursor=current_cursor, |
Comment on lines
+21
to
+22
| Returns the decoded JSON body on success; returns None after exhausting retries. | ||
| Callers must handle the None case (critical failures). |
Comment on lines
+31
to
+32
| except requests.RequestException as e: | ||
| log.warning(f"Network error (attempt {attempt}/{__MAX_ATTEMPTS}) url={url} error={e}") |
Comment on lines
+50
to
+52
| if resp.status_code != 200: | ||
| log.severe(f"Non-success status {resp.status_code} url={url} body={resp.text[:300]}") | ||
| return None |
Comment on lines
+59
to
+62
| def _convert_time_to_unix(timestr: str) -> int: | ||
| """Convert a Graph API-formatted UTC timestamp string to a Unix epoch timestamp.""" | ||
| dt = datetime.strptime(timestr, "%Y-%m-%dT%H:%M:%S+0000") | ||
| return int(dt.timestamp()) |
| def _paginate_graph_collection( | ||
| path: str, params: Dict[str, Any] | None, cfg: Dict[str, Any] | ||
| ) -> Iterator[Dict[str, Any]]: | ||
| """Generator that walks Graph API paging via the `next` cursor.""" |
Comment on lines
+3
to
+5
| from __future__ import annotations | ||
| from datetime import datetime | ||
| from typing import Dict, Any, List, Optional |
| ) | ||
|
|
||
| def _list(key: str) -> Optional[List[str]]: | ||
| """Parse a comma-separated configuration value into an ID list, or None for 'ALL'.""" |
|
|
||
|
|
||
| def validate_page_access_tokens(pages: List[Dict[str, Any]]) -> None: | ||
| """Raise if any discovered page is missing an access token needed to sync its forms.""" |
| minimum: Optional[int] = None, | ||
| maximum: Optional[int] = None, | ||
| ) -> int: | ||
| """Parse a configuration value as an integer, applying a default and range checks.""" |
fivetran-satvikpatil
left a comment
Contributor
There was a problem hiding this comment.
@fivetran-tanishk please address the copilot comments.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Summary
leadstable via the Meta Graph API.page_ids/form_ids, per-form incremental sync oncreated_time, and threshold-based checkpointing to bound replay volume on failure.README.mdconnector list.Test plan
python -m py_compilepasses on all connector files.black --line-length 99andflake8(repo.flake8config) pass with zero findings.🤖 Generated with Claude Code