feat(data-warehouse): implement tremendous import source - #69377
Merged
Conversation
Implements the Tremendous warehouse source end-to-end: seven endpoint catalog (orders, rewards, invoices, members, campaigns, products, funding_sources), resumable offset pagination, incremental sync on orders via created_at[gte], sandbox/production environment select, canonical table descriptions, and tests. Generated-By: PostHog Code Task-Id: 328131bb-785b-4a7e-bc74-ff7a15cb7459
Contributor
|
Hey @Gilbert09! 👋 It looks like your git author email on this PR isn't your
You can fix it for this repo with: git config user.email "you@posthog.com"Or set it globally with |
Contributor
|
Reviews (1): Last reviewed commit: "feat(data-warehouse): implement tremendo..." | Re-trigger Greptile |
…t config The endpoint name already lives in the TREMENDOUS_ENDPOINTS dict key and nothing reads the field. Flagged by review. Generated-By: PostHog Code Task-Id: 328131bb-785b-4a7e-bc74-ff7a15cb7459
Credentialed Tremendous requests carry a Bearer API key. With redirects enabled, a 30x response (or an on-path actor inducing one) would replay the authenticated request to a different host, leaking the key past the connector's outbound trust boundary. Pass allow_redirects=False on both the sync session and the credential-validation probe so requests stay pinned to the validated host. Generated-By: PostHog Code Task-Id: 6636b133-8f49-4793-b252-8ed55fba633e
Generated-By: PostHog Code Task-Id: 6636b133-8f49-4793-b252-8ed55fba633e
MarconLP
approved these changes
Jul 9, 2026
MarconLP
approved these changes
Jul 9, 2026
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.
Problem
Tremendous (rewards and incentives payouts: gift cards, prepaid cards, cash) was scaffolded as a warehouse source but had no sync logic, so users couldn't pull their payouts data into the Data warehouse to analyze incentive programs alongside product data.
Changes
Fills in the
tremendoussource following the standardsource.py/settings.py/tremendous.pysplit:settings.py):orders,rewards,invoices,members,campaigns,products,funding_sources. Primary key isideverywhere.orders/rewards/invoicespartition bycreated_at(stable creation timestamp).ordersexposes a server-side timestamp filter (created_at[gte], ISO 8601), confirmed against Tremendous's official OpenAPI spec, so it's the only incremental endpoint. Everything else is full refresh.balance_transactionsalso filters oncreated_atbut its rows carry noid(no usable primary key), so it's deliberately excluded for now.tremendous.py):requestsviamake_tracked_session(), tenacity retries on 429/5xx, offset/limit pagination (per-endpoint page caps from the spec: orders/rewards 500, invoices 10). Tremendous lists are creation-date DESC with no sort param, sosort_mode="desc"and the incremental watermark finalizes at the end of a completed sync.members/campaigns/products/funding_sourcesare unpaginated single-response collections.ResumableSource): offset saved to Redis after each yielded page, so a heartbeat-timeout retry resumes mid-collection instead of restarting; re-pulled rows dedupe on the primary key.get_non_retryable_errorsfor 401/403 on both hosts, org-wide single-probevalidate_credentials,canonical_descriptions.pyfrom the official API reference,lists_tables_without_credentials = Trueso public docs render the table catalog.SOURCES.md: movedtremendousfrom Scaffolded into the Implemented table (HTTP / requests / tracked).generated_configs.py: regenerated; diff kept to theTremendousSourceConfigclass only.Note
Webhooks are intentionally not wired up. Tremendous allows exactly one webhook endpoint per organization, so auto-creating ours would clobber any webhook the customer already relies on. Pull-only for now; noted in a code comment.
The source stays behind
unreleasedSource=TruewithreleaseStatus=ALPHAfor a staged rollout. Enum/schema wiring (types.py,schema-general.ts,schema_enums.py) and the icon landed with the scaffold; no migrations needed.Endpoint behavior (pagination params, response shapes, filter semantics, per-endpoint limit caps) was verified against Tremendous's published OpenAPI spec and unauthenticated probes of the live sandbox API (all endpoints return 401, confirming paths). I couldn't run authenticated smoke tests without an API key, so filter behavior follows the spec; the conservative bits (inclusive
gtere-fetch deduped by merge, short-page termination) are documented in code comments.How did you test this code?
Automated only (no Tremendous credentials available for a live sync):
test_tremendous.py(transport): offset pagination advances and terminates on a short page (guards infinite-loop/missed-page regressions), resume starts from the saved offset instead of page one, state saves only after a yielded page (crash-safety ordering),created_at[gte]is sent on every page when incremental and never on full refresh (guards silent full re-syncs and windowed full refreshes), unpaginated endpoints fetch once with no params, retryable vs terminal status mapping, environment-to-host routing,SourceResponseshape (sort_mode="desc", stable partition keys).test_tremendous_source.py(source class): onlyordersadvertises incremental, documented-tables rendering via the placeholder config path, non-retryable error keys match real 401/403 URLs on both hosts but not transient 429/5xx, credential/environment plumbing, a stale watermark is dropped on full-refresh runs, unknown schema rejected.ruff check/formatclean,hogli ci:preflight --fixreports 0 failures,makemigrations --checkreports no changes.Automatic notifications
Docs update
The posthog.com doc (
contents/docs/cdp/sources/tremendous.md) is written per the docs template and validated withaudit_source_docsagainst a posthog.com checkout (no Tremendous findings), but it lives in the posthog.com repo and needs to land there separately:tremendous.md for posthog.com
🤖 Agent context
Autonomy: Human-driven (agent-assisted)
Authored with Claude Code from a task brief. Skills invoked:
/implementing-warehouse-sources(architecture contract, incremental/resumable rules),/writing-tests(test value gate),/documenting-warehouse-sources(doc template + audit).Decisions along the way: chose
ResumableSourcewithoutWebhookSourcebecause of the one-webhook-per-org constraint; excludedbalance_transactions(noidon rows); declaredsort_mode="desc"after confirming from the OpenAPI spec that lists are creation-DESC with no sort param; per-endpoint page caps taken from the spec (invoices is capped at 10, not 500). The generator rewrote unrelated classes ingenerated_configs.py, so its diff was manually restricted to the Tremendous class.Created with PostHog Code