diff --git a/frontend/public/services/shipmail.png b/frontend/public/services/shipmail.png new file mode 100644 index 000000000000..8a53e4a42253 Binary files /dev/null and b/frontend/public/services/shipmail.png differ diff --git a/frontend/src/queries/schema.json b/frontend/src/queries/schema.json index d22b63b58618..41760b266e8b 100644 --- a/frontend/src/queries/schema.json +++ b/frontend/src/queries/schema.json @@ -23317,6 +23317,7 @@ "Ebay", "Commercetools", "LightspeedRetail", + "Shipmail", "ShipStation", "ConstantContact", "Mailgun", diff --git a/frontend/src/queries/schema/schema-general.ts b/frontend/src/queries/schema/schema-general.ts index aae24ad17475..52f2343977c6 100644 --- a/frontend/src/queries/schema/schema-general.ts +++ b/frontend/src/queries/schema/schema-general.ts @@ -7141,6 +7141,7 @@ export const externalDataSources = [ 'Ebay', 'Commercetools', 'LightspeedRetail', + 'Shipmail', 'ShipStation', 'ConstantContact', 'Mailgun', diff --git a/posthog/schema_enums.py b/posthog/schema_enums.py index aad7c01777fe..4ad788206301 100644 --- a/posthog/schema_enums.py +++ b/posthog/schema_enums.py @@ -1363,6 +1363,7 @@ class ExternalDataSourceType(StrEnum): EBAY = "Ebay" COMMERCETOOLS = "Commercetools" LIGHTSPEED_RETAIL = "LightspeedRetail" + SHIPMAIL = "Shipmail" SHIP_STATION = "ShipStation" CONSTANT_CONTACT = "ConstantContact" MAILGUN = "Mailgun" diff --git a/products/data_warehouse/frontend/generated/api.schemas.ts b/products/data_warehouse/frontend/generated/api.schemas.ts index ea5989b161ac..f617b66c2dd5 100644 --- a/products/data_warehouse/frontend/generated/api.schemas.ts +++ b/products/data_warehouse/frontend/generated/api.schemas.ts @@ -1457,6 +1457,7 @@ export interface CredentialApi { * * `Ebay` - Ebay * * `Commercetools` - Commercetools * * `LightspeedRetail` - LightspeedRetail + * * `Shipmail` - Shipmail * * `ShipStation` - ShipStation * * `ConstantContact` - ConstantContact * * `Mailgun` - Mailgun @@ -2738,6 +2739,7 @@ export const ExternalDataSourceTypeEnumApi = { Ebay: 'Ebay', Commercetools: 'Commercetools', LightspeedRetail: 'LightspeedRetail', + Shipmail: 'Shipmail', ShipStation: 'ShipStation', ConstantContact: 'ConstantContact', Mailgun: 'Mailgun', diff --git a/products/warehouse_sources/backend/migrations/0116_shipmail_source.py b/products/warehouse_sources/backend/migrations/0116_shipmail_source.py new file mode 100644 index 000000000000..410ebe618854 --- /dev/null +++ b/products/warehouse_sources/backend/migrations/0116_shipmail_source.py @@ -0,0 +1,2590 @@ +# Generated by Django 5.2.14 on 2026-07-31 10:37 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("warehouse_sources", "0115_scaffold_four_requested_sources"), + ] + + operations = [ + migrations.AlterField( + model_name="externaldatasource", + name="source_type", + field=models.CharField( + choices=[ + ("Ashby", "Ashby"), + ("Supabase", "Supabase"), + ("CustomerIO", "CustomerIO"), + ("Github", "Github"), + ("Stripe", "Stripe"), + ("Hubspot", "Hubspot"), + ("Postgres", "Postgres"), + ("Zendesk", "Zendesk"), + ("Snowflake", "Snowflake"), + ("Salesforce", "Salesforce"), + ("MySQL", "MySQL"), + ("MongoDB", "MongoDB"), + ("MSSQL", "MSSQL"), + ("Vitally", "Vitally"), + ("BigQuery", "BigQuery"), + ("Chargebee", "Chargebee"), + ("Clerk", "Clerk"), + ("GoogleAds", "GoogleAds"), + ("GoogleSearchConsole", "GoogleSearchConsole"), + ("TemporalIO", "TemporalIO"), + ("DoIt", "DoIt"), + ("GoogleSheets", "GoogleSheets"), + ("MetaAds", "MetaAds"), + ("Klaviyo", "Klaviyo"), + ("Mailchimp", "Mailchimp"), + ("Braze", "Braze"), + ("Mailjet", "Mailjet"), + ("Redshift", "Redshift"), + ("Polar", "Polar"), + ("RevenueCat", "RevenueCat"), + ("LinkedinAds", "LinkedinAds"), + ("RedditAds", "RedditAds"), + ("TikTokAds", "TikTokAds"), + ("BingAds", "BingAds"), + ("Shopify", "Shopify"), + ("Attio", "Attio"), + ("SnapchatAds", "SnapchatAds"), + ("Linear", "Linear"), + ("Intercom", "Intercom"), + ("Amplitude", "Amplitude"), + ("Mixpanel", "Mixpanel"), + ("Jira", "Jira"), + ("ActiveCampaign", "ActiveCampaign"), + ("Marketo", "Marketo"), + ("Adjust", "Adjust"), + ("AppsFlyer", "AppsFlyer"), + ("Freshdesk", "Freshdesk"), + ("GoogleAnalytics", "GoogleAnalytics"), + ("Pipedrive", "Pipedrive"), + ("SendGrid", "SendGrid"), + ("Slack", "Slack"), + ("PagerDuty", "PagerDuty"), + ("Asana", "Asana"), + ("Notion", "Notion"), + ("Airtable", "Airtable"), + ("Greenhouse", "Greenhouse"), + ("BambooHR", "BambooHR"), + ("Lever", "Lever"), + ("GitLab", "GitLab"), + ("Datadog", "Datadog"), + ("Sentry", "Sentry"), + ("Pendo", "Pendo"), + ("FullStory", "FullStory"), + ("AmazonAds", "AmazonAds"), + ("PinterestAds", "PinterestAds"), + ("AppleSearchAds", "AppleSearchAds"), + ("QuickBooks", "QuickBooks"), + ("Xero", "Xero"), + ("NetSuite", "NetSuite"), + ("WooCommerce", "WooCommerce"), + ("BigCommerce", "BigCommerce"), + ("PayPal", "PayPal"), + ("Square", "Square"), + ("Zoom", "Zoom"), + ("Trello", "Trello"), + ("Monday", "Monday"), + ("ClickUp", "ClickUp"), + ("Confluence", "Confluence"), + ("Recurly", "Recurly"), + ("SalesLoft", "SalesLoft"), + ("Outreach", "Outreach"), + ("Gong", "Gong"), + ("Calendly", "Calendly"), + ("Typeform", "Typeform"), + ("Iterable", "Iterable"), + ("ZohoCRM", "ZohoCRM"), + ("Close", "Close"), + ("Oracle", "Oracle"), + ("DynamoDB", "DynamoDB"), + ("Elasticsearch", "Elasticsearch"), + ("Kafka", "Kafka"), + ("LaunchDarkly", "LaunchDarkly"), + ("Braintree", "Braintree"), + ("Recharge", "Recharge"), + ("HelpScout", "HelpScout"), + ("Gorgias", "Gorgias"), + ("Instagram", "Instagram"), + ("YouTubeAnalytics", "YouTubeAnalytics"), + ("FacebookPages", "FacebookPages"), + ("TwitterAds", "TwitterAds"), + ("Workday", "Workday"), + ("ServiceNow", "ServiceNow"), + ("Pardot", "Pardot"), + ("Copper", "Copper"), + ("Front", "Front"), + ("ChartMogul", "ChartMogul"), + ("Zuora", "Zuora"), + ("Paddle", "Paddle"), + ("CircleCI", "CircleCI"), + ("CockroachDB", "CockroachDB"), + ("Firebase", "Firebase"), + ("AzureBlob", "AzureBlob"), + ("GoogleDrive", "GoogleDrive"), + ("OneDrive", "OneDrive"), + ("SharePoint", "SharePoint"), + ("Box", "Box"), + ("SFTP", "SFTP"), + ("MicrosoftTeams", "MicrosoftTeams"), + ("Aircall", "Aircall"), + ("Webflow", "Webflow"), + ("Okta", "Okta"), + ("Auth0", "Auth0"), + ("Productboard", "Productboard"), + ("Smartsheet", "Smartsheet"), + ("Wrike", "Wrike"), + ("Plaid", "Plaid"), + ("SurveyMonkey", "SurveyMonkey"), + ("Eventbrite", "Eventbrite"), + ("RingCentral", "RingCentral"), + ("Twilio", "Twilio"), + ("Freshsales", "Freshsales"), + ("Shortcut", "Shortcut"), + ("ConvertKit", "ConvertKit"), + ("Drip", "Drip"), + ("CampaignMonitor", "CampaignMonitor"), + ("MailerLite", "MailerLite"), + ("Omnisend", "Omnisend"), + ("Brevo", "Brevo"), + ("Postmark", "Postmark"), + ("Granola", "Granola"), + ("BuildBetter", "BuildBetter"), + ("Convex", "Convex"), + ("ClickHouse", "ClickHouse"), + ("Plain", "Plain"), + ("Resend", "Resend"), + ("PgAnalyze", "PgAnalyze"), + ("WorkOS", "WorkOS"), + ("AmazonS3", "AmazonS3"), + ("GoogleCloudStorage", "GoogleCloudStorage"), + ("Databricks", "Databricks"), + ("Dynamics365", "Dynamics365"), + ("SalesforceMarketingCloud", "SalesforceMarketingCloud"), + ("Db2", "Db2"), + ("Heap", "Heap"), + ("AdobeAnalytics", "AdobeAnalytics"), + ("Matomo", "Matomo"), + ("Optimizely", "Optimizely"), + ("Adyen", "Adyen"), + ("GoCardless", "GoCardless"), + ("Mollie", "Mollie"), + ("CheckoutCom", "CheckoutCom"), + ("Branch", "Branch"), + ("Criteo", "Criteo"), + ("Outbrain", "Outbrain"), + ("Taboola", "Taboola"), + ("AdRoll", "AdRoll"), + ("DisplayVideo360", "DisplayVideo360"), + ("GoogleAdManager", "GoogleAdManager"), + ("CampaignManager360", "CampaignManager360"), + ("SearchAds360", "SearchAds360"), + ("AdobeCommerce", "AdobeCommerce"), + ("AmazonSellingPartner", "AmazonSellingPartner"), + ("Ebay", "Ebay"), + ("Commercetools", "Commercetools"), + ("LightspeedRetail", "LightspeedRetail"), + ("Shipmail", "Shipmail"), + ("ShipStation", "ShipStation"), + ("ConstantContact", "ConstantContact"), + ("Mailgun", "Mailgun"), + ("Eloqua", "Eloqua"), + ("Sailthru", "Sailthru"), + ("Ortto", "Ortto"), + ("Attentive", "Attentive"), + ("Kustomer", "Kustomer"), + ("Dixa", "Dixa"), + ("Gladly", "Gladly"), + ("Qualtrics", "Qualtrics"), + ("AzureDevOps", "AzureDevOps"), + ("Rollbar", "Rollbar"), + ("Opsgenie", "Opsgenie"), + ("IncidentIo", "IncidentIo"), + ("Pingdom", "Pingdom"), + ("Cloudflare", "Cloudflare"), + ("CosmosDB", "CosmosDB"), + ("PlanetScale", "PlanetScale"), + ("SapHana", "SapHana"), + ("Rippling", "Rippling"), + ("HiBob", "HiBob"), + ("Personio", "Personio"), + ("Deel", "Deel"), + ("AdpWorkforceNow", "AdpWorkforceNow"), + ("Paylocity", "Paylocity"), + ("Gusto", "Gusto"), + ("CultureAmp", "CultureAmp"), + ("Lattice", "Lattice"), + ("SageIntacct", "SageIntacct"), + ("FreshBooks", "FreshBooks"), + ("Expensify", "Expensify"), + ("Ramp", "Ramp"), + ("Brex", "Brex"), + ("Coupa", "Coupa"), + ("SapConcur", "SapConcur"), + ("Apollo", "Apollo"), + ("Crunchbase", "Crunchbase"), + ("ZoomInfo", "ZoomInfo"), + ("Clari", "Clari"), + ("Chorus", "Chorus"), + ("Coda", "Coda"), + ("Guru", "Guru"), + ("Dropbox", "Dropbox"), + ("Docusign", "Docusign"), + ("PandaDoc", "PandaDoc"), + ("SapErp", "SapErp"), + ("SapSuccessFactors", "SapSuccessFactors"), + ("OracleEbs", "OracleEbs"), + ("OracleFusion", "OracleFusion"), + ("AmazonSNS", "AmazonSNS"), + ("AmazonEventBridge", "AmazonEventBridge"), + ("AmazonSQS", "AmazonSQS"), + ("AmazonKinesis", "AmazonKinesis"), + ("AmazonCloudWatch", "AmazonCloudWatch"), + ("OpenAIAds", "OpenAIAds"), + ("OneHundredMs", "OneHundredMs"), + ("SevenShifts", "SevenShifts"), + ("AcuityScheduling", "AcuityScheduling"), + ("AgileCRM", "AgileCRM"), + ("Aha", "Aha"), + ("Airbyte", "Airbyte"), + ("Akeneo", "Akeneo"), + ("Algolia", "Algolia"), + ("AlpacaBrokerAPI", "AlpacaBrokerAPI"), + ("ApifyDataset", "ApifyDataset"), + ("Appcues", "Appcues"), + ("Appfigures", "Appfigures"), + ("Appfollow", "Appfollow"), + ("Apptivo", "Apptivo"), + ("AssemblyAI", "AssemblyAI"), + ("Awin", "Awin"), + ("AwsCloudTrail", "AwsCloudTrail"), + ("AzureTableStorage", "AzureTableStorage"), + ("Babelforce", "Babelforce"), + ("Basecamp", "Basecamp"), + ("Beamer", "Beamer"), + ("BigMailer", "BigMailer"), + ("Bluetally", "Bluetally"), + ("BoldSign", "BoldSign"), + ("BreezyHR", "BreezyHR"), + ("Bugsnag", "Bugsnag"), + ("Buildkite", "Buildkite"), + ("Bunny", "Bunny"), + ("Buzzsprout", "Buzzsprout"), + ("CalCom", "CalCom"), + ("CallRail", "CallRail"), + ("Campayn", "Campayn"), + ("Canny", "Canny"), + ("CapsuleCRM", "CapsuleCRM"), + ("CaptainData", "CaptainData"), + ("CartCom", "CartCom"), + ("CastorEDC", "CastorEDC"), + ("Chameleon", "Chameleon"), + ("Chargedesk", "Chargedesk"), + ("Chargify", "Chargify"), + ("Chift", "Chift"), + ("Churnkey", "Churnkey"), + ("Cin7", "Cin7"), + ("CiscoMeraki", "CiscoMeraki"), + ("Clazar", "Clazar"), + ("Clockify", "Clockify"), + ("Clockodo", "Clockodo"), + ("Cloudbeds", "Cloudbeds"), + ("Coassemble", "Coassemble"), + ("Codefresh", "Codefresh"), + ("Concord", "Concord"), + ("ConfigCat", "ConfigCat"), + ("Couchbase", "Couchbase"), + ("Curve", "Curve"), + ("Customerly", "Customerly"), + ("Datascope", "Datascope"), + ("Dbt", "Dbt"), + ("Deputy", "Deputy"), + ("DevinAI", "DevinAI"), + ("Docuseal", "Docuseal"), + ("Dolibarr", "Dolibarr"), + ("Dremio", "Dremio"), + ("DropboxSign", "DropboxSign"), + ("Dwolla", "Dwolla"), + ("EConomic", "EConomic"), + ("Easypost", "Easypost"), + ("Easypromos", "Easypromos"), + ("Elasticemail", "Elasticemail"), + ("EmailOctopus", "EmailOctopus"), + ("EmploymentHero", "EmploymentHero"), + ("Encharge", "Encharge"), + ("Eventee", "Eventee"), + ("Eventzilla", "Eventzilla"), + ("Everhour", "Everhour"), + ("EZOfficeInventory", "EZOfficeInventory"), + ("Factorial", "Factorial"), + ("Fastbill", "Fastbill"), + ("Fastly", "Fastly"), + ("Fauna", "Fauna"), + ("Feishu", "Feishu"), + ("Fillout", "Fillout"), + ("Finage", "Finage"), + ("Firebolt", "Firebolt"), + ("FireHydrant", "FireHydrant"), + ("Fleetio", "Fleetio"), + ("Flexmail", "Flexmail"), + ("Flexport", "Flexport"), + ("FloatApp", "FloatApp"), + ("Flowlu", "Flowlu"), + ("Formbricks", "Formbricks"), + ("FreeAgent", "FreeAgent"), + ("Freightview", "Freightview"), + ("Freshcaller", "Freshcaller"), + ("Freshchat", "Freshchat"), + ("Freshservice", "Freshservice"), + ("Fulcrum", "Fulcrum"), + ("GainsightPx", "GainsightPx"), + ("GitBook", "GitBook"), + ("Glassfrog", "Glassfrog"), + ("Goldcast", "Goldcast"), + ("GoLogin", "GoLogin"), + ("Grafana", "Grafana"), + ("GreytHr", "GreytHr"), + ("Gridly", "Gridly"), + ("Harness", "Harness"), + ("Height", "Height"), + ("Hellobaton", "Hellobaton"), + ("HighLevel", "HighLevel"), + ("HoorayHR", "HoorayHR"), + ("Hubplanner", "Hubplanner"), + ("Humanitix", "Humanitix"), + ("Huntr", "Huntr"), + ("Inflowinventory", "Inflowinventory"), + ("InforNexus", "InforNexus"), + ("Insightful", "Insightful"), + ("Insightly", "Insightly"), + ("Instantly", "Instantly"), + ("Instatus", "Instatus"), + ("Intruder", "Intruder"), + ("Invoiced", "Invoiced"), + ("Invoiceninja", "Invoiceninja"), + ("JamfPro", "JamfPro"), + ("JobNimbus", "JobNimbus"), + ("Jotform", "Jotform"), + ("JudgeMeReviews", "JudgeMeReviews"), + ("JustCall", "JustCall"), + ("JustSift", "JustSift"), + ("K6Cloud", "K6Cloud"), + ("Katana", "Katana"), + ("Keka", "Keka"), + ("Kisi", "Kisi"), + ("Kissmetrics", "Kissmetrics"), + ("Klarna", "Klarna"), + ("Klaus", "Klaus"), + ("Lago", "Lago"), + ("Leadfeeder", "Leadfeeder"), + ("Lemlist", "Lemlist"), + ("LessAnnoyingCRM", "LessAnnoyingCRM"), + ("LinkedinPages", "LinkedinPages"), + ("Linkrunner", "Linkrunner"), + ("Linnworks", "Linnworks"), + ("Lob", "Lob"), + ("Lokalise", "Lokalise"), + ("Looker", "Looker"), + ("Luma", "Luma"), + ("MailerSend", "MailerSend"), + ("Mailosaur", "Mailosaur"), + ("Mailtrap", "Mailtrap"), + ("Mantle", "Mantle"), + ("Mention", "Mention"), + ("MercadoAds", "MercadoAds"), + ("Merge", "Merge"), + ("Metabase", "Metabase"), + ("Metricool", "Metricool"), + ("MicrosoftDataverse", "MicrosoftDataverse"), + ("MicrosoftEntraId", "MicrosoftEntraId"), + ("MicrosoftLists", "MicrosoftLists"), + ("Miro", "Miro"), + ("Missive", "Missive"), + ("MixMax", "MixMax"), + ("Mode", "Mode"), + ("Mux", "Mux"), + ("MyHours", "MyHours"), + ("N8n", "N8n"), + ("Navan", "Navan"), + ("NebiusAI", "NebiusAI"), + ("Nexiopay", "Nexiopay"), + ("NinjaOneRMM", "NinjaOneRMM"), + ("NoCRM", "NoCRM"), + ("NorthpassLMS", "NorthpassLMS"), + ("Nutshell", "Nutshell"), + ("Nylas", "Nylas"), + ("Oncehub", "Oncehub"), + ("Onepagecrm", "Onepagecrm"), + ("OneSignal", "OneSignal"), + ("Onfleet", "Onfleet"), + ("OpinionStage", "OpinionStage"), + ("OPUSWatch", "OPUSWatch"), + ("Orb", "Orb"), + ("Orbit", "Orbit"), + ("Oura", "Oura"), + ("Oveit", "Oveit"), + ("PabblySubscriptionsBilling", "PabblySubscriptionsBilling"), + ("Paperform", "Paperform"), + ("Papersign", "Papersign"), + ("Partnerize", "Partnerize"), + ("PartnerStack", "PartnerStack"), + ("PayFit", "PayFit"), + ("Paystack", "Paystack"), + ("Pennylane", "Pennylane"), + ("Perk", "Perk"), + ("PersistIq", "PersistIq"), + ("Persona", "Persona"), + ("Phyllo", "Phyllo"), + ("Picqer", "Picqer"), + ("Pipeliner", "Pipeliner"), + ("PivotalTracker", "PivotalTracker"), + ("Piwik", "Piwik"), + ("Planhat", "Planhat"), + ("Plausible", "Plausible"), + ("Poplar", "Poplar"), + ("PrestaShop", "PrestaShop"), + ("Pretix", "Pretix"), + ("Primetric", "Primetric"), + ("Printavo", "Printavo"), + ("Printify", "Printify"), + ("Productive", "Productive"), + ("Pylon", "Pylon"), + ("Qonto", "Qonto"), + ("Qualaroo", "Qualaroo"), + ("Railz", "Railz"), + ("RDStationMarketing", "RDStationMarketing"), + ("Recruitee", "Recruitee"), + ("Reddit", "Reddit"), + ("ReferralHero", "ReferralHero"), + ("RentCast", "RentCast"), + ("Repairshopr", "Repairshopr"), + ("ReplyIo", "ReplyIo"), + ("RetailExpress", "RetailExpress"), + ("Retently", "Retently"), + ("RevolutMerchant", "RevolutMerchant"), + ("RocketChat", "RocketChat"), + ("Rocketlane", "Rocketlane"), + ("Rootly", "Rootly"), + ("Ruddr", "Ruddr"), + ("SafetyCulture", "SafetyCulture"), + ("SageHR", "SageHR"), + ("Salesflare", "Salesflare"), + ("SAPFieldglass", "SAPFieldglass"), + ("SavvyCal", "SavvyCal"), + ("Secoda", "Secoda"), + ("Segment", "Segment"), + ("Sendowl", "Sendowl"), + ("SendPulse", "SendPulse"), + ("Senseforce", "Senseforce"), + ("Serpstat", "Serpstat"), + ("Sharetribe", "Sharetribe"), + ("Shippo", "Shippo"), + ("ShopWired", "ShopWired"), + ("Shortio", "Shortio"), + ("Shutterstock", "Shutterstock"), + ("SigmaComputing", "SigmaComputing"), + ("SignNow", "SignNow"), + ("SimpleCast", "SimpleCast"), + ("Simplesat", "Simplesat"), + ("Smaily", "Smaily"), + ("SmartEngage", "SmartEngage"), + ("Smartreach", "Smartreach"), + ("Smartwaiver", "Smartwaiver"), + ("SolarwindsServiceDesk", "SolarwindsServiceDesk"), + ("SonarCloud", "SonarCloud"), + ("SparkPost", "SparkPost"), + ("SplitIo", "SplitIo"), + ("SpotifyAds", "SpotifyAds"), + ("SpotlerCRM", "SpotlerCRM"), + ("Squarespace", "Squarespace"), + ("Statsig", "Statsig"), + ("Statuspage", "Statuspage"), + ("Stigg", "Stigg"), + ("Strava", "Strava"), + ("SurveySparrow", "SurveySparrow"), + ("Survicate", "Survicate"), + ("Svix", "Svix"), + ("Systeme", "Systeme"), + ("Tavus", "Tavus"), + ("Teamtailor", "Teamtailor"), + ("Teamwork", "Teamwork"), + ("Tempo", "Tempo"), + ("Testrail", "Testrail"), + ("Thinkific", "Thinkific"), + ("ThinkificCourses", "ThinkificCourses"), + ("ThriveLearning", "ThriveLearning"), + ("Ticketmaster", "Ticketmaster"), + ("TicketTailor", "TicketTailor"), + ("TickTick", "TickTick"), + ("Timely", "Timely"), + ("Tinyemail", "Tinyemail"), + ("Todoist", "Todoist"), + ("Toggl", "Toggl"), + ("TrackPMS", "TrackPMS"), + ("Tremendous", "Tremendous"), + ("TrustPilot", "TrustPilot"), + ("Twitter", "Twitter"), + ("TyntecSMS", "TyntecSMS"), + ("Unleash", "Unleash"), + ("UpPromote", "UpPromote"), + ("Uptick", "Uptick"), + ("Uservoice", "Uservoice"), + ("Vantage", "Vantage"), + ("Veeqo", "Veeqo"), + ("Vercel", "Vercel"), + ("VismaEconomic", "VismaEconomic"), + ("VWO", "VWO"), + ("Waiteraid", "Waiteraid"), + ("Wasabi", "Wasabi"), + ("WhenIWork", "WhenIWork"), + ("Wordpress", "Wordpress"), + ("Workable", "Workable"), + ("Workflowmax", "Workflowmax"), + ("Workramp", "Workramp"), + ("Wufoo", "Wufoo"), + ("Xsolla", "Xsolla"), + ("YandexMetrica", "YandexMetrica"), + ("Yotpo", "Yotpo"), + ("Ynab", "Ynab"), + ("Younium", "Younium"), + ("YouSign", "YouSign"), + ("YoutubeData", "YoutubeData"), + ("ZapierSupportedStorage", "ZapierSupportedStorage"), + ("ZapSign", "ZapSign"), + ("ZendeskSell", "ZendeskSell"), + ("ZendeskSunshine", "ZendeskSunshine"), + ("Zenefits", "Zenefits"), + ("Zenloop", "Zenloop"), + ("ZohoAnalytics", "ZohoAnalytics"), + ("ZohoBigin", "ZohoBigin"), + ("ZohoBilling", "ZohoBilling"), + ("ZohoBooks", "ZohoBooks"), + ("ZohoCampaign", "ZohoCampaign"), + ("ZohoDesk", "ZohoDesk"), + ("ZohoExpense", "ZohoExpense"), + ("ZohoInventory", "ZohoInventory"), + ("ZohoInvoice", "ZohoInvoice"), + ("ZonkaFeedback", "ZonkaFeedback"), + ("AlphaVantage", "AlphaVantage"), + ("Aviationstack", "Aviationstack"), + ("Bitly", "Bitly"), + ("Blogger", "Blogger"), + ("Breezometer", "Breezometer"), + ("CareQualityCommission", "CareQualityCommission"), + ("Cimis", "Cimis"), + ("CoinApi", "CoinApi"), + ("CoinGecko", "CoinGecko"), + ("CoinMarketCap", "CoinMarketCap"), + ("DingConnect", "DingConnect"), + ("Dockerhub", "Dockerhub"), + ("ExchangeRatesApi", "ExchangeRatesApi"), + ("FinancialModelling", "FinancialModelling"), + ("Finnhub", "Finnhub"), + ("Finnworlds", "Finnworlds"), + ("Giphy", "Giphy"), + ("Gmail", "Gmail"), + ("GNews", "GNews"), + ("GoogleCalendar", "GoogleCalendar"), + ("GoogleClassroom", "GoogleClassroom"), + ("GoogleDirectory", "GoogleDirectory"), + ("GoogleForms", "GoogleForms"), + ("GooglePageSpeedInsights", "GooglePageSpeedInsights"), + ("GoogleTasks", "GoogleTasks"), + ("GoogleWebfonts", "GoogleWebfonts"), + ("GoogleWorkspaceAdminReports", "GoogleWorkspaceAdminReports"), + ("HuggingFace", "HuggingFace"), + ("IlluminaBasespace", "IlluminaBasespace"), + ("Imagga", "Imagga"), + ("Interzoid", "Interzoid"), + ("IP2Whois", "IP2Whois"), + ("KYVE", "KYVE"), + ("Marketstack", "Marketstack"), + ("Mendeley", "Mendeley"), + ("Nasa", "Nasa"), + ("NewYorkTimes", "NewYorkTimes"), + ("NewsApi", "NewsApi"), + ("NewsData", "NewsData"), + ("OpenDataDc", "OpenDataDc"), + ("OpenExchangeRates", "OpenExchangeRates"), + ("OpenAQ", "OpenAQ"), + ("OpenFDA", "OpenFDA"), + ("OpenWeather", "OpenWeather"), + ("Outlook", "Outlook"), + ("Perigon", "Perigon"), + ("Pexels", "Pexels"), + ("Pocket", "Pocket"), + ("Polygon", "Polygon"), + ("PyPI", "PyPI"), + ("Recreation", "Recreation"), + ("RKICovid", "RKICovid"), + ("Rss", "Rss"), + ("SimFin", "SimFin"), + ("StockData", "StockData"), + ("Guardian", "Guardian"), + ("TMDb", "TMDb"), + ("TVMaze", "TVMaze"), + ("TwelveData", "TwelveData"), + ("Ubidots", "Ubidots"), + ("USCensus", "USCensus"), + ("Watchmode", "Watchmode"), + ("WikipediaPageviews", "WikipediaPageviews"), + ("YahooFinance", "YahooFinance"), + ("Clarifai", "Clarifai"), + ("Adapty", "Adapty"), + ("Braintrust", "Braintrust"), + ("StreamElements", "StreamElements"), + ("Streamlabs", "Streamlabs"), + ("Datorama", "Datorama"), + ("Ahrefs", "Ahrefs"), + ("Lightfield", "Lightfield"), + ("Appstack", "Appstack"), + ("Razorpay", "Razorpay"), + ("Neon", "Neon"), + ("NewRelic", "NewRelic"), + ("Custom", "Custom"), + ("Tile38", "Tile38"), + ("Chatwoot", "Chatwoot"), + ("Sanity", "Sanity"), + ("Metronome", "Metronome"), + ("Jobber", "Jobber"), + ("Knock", "Knock"), + ("Leexi", "Leexi"), + ("RB2B", "RB2B"), + ("Superwall", "Superwall"), + ("Liana", "Liana"), + ("TawkTo", "TawkTo"), + ("Hightouch", "Hightouch"), + ("LemonSqueezy", "LemonSqueezy"), + ("Ikas", "Ikas"), + ("Talkwalker", "Talkwalker"), + ("NextdoorAds", "NextdoorAds"), + ("AppLovin", "AppLovin"), + ("Baserow", "Baserow"), + ("Plunk", "Plunk"), + ("Dub", "Dub"), + ("AirOps", "AirOps"), + ("Podium", "Podium"), + ("Loops", "Loops"), + ("Redis", "Redis"), + ("Mercury", "Mercury"), + ("Gojiberry", "Gojiberry"), + ("Teachable", "Teachable"), + ("PeecAI", "PeecAI"), + ("Healthchecks", "Healthchecks"), + ("Impact", "Impact"), + ("AikidoSecurity", "AikidoSecurity"), + ("Alguna", "Alguna"), + ("Anthropic", "Anthropic"), + ("Appwrite", "Appwrite"), + ("BlandAI", "BlandAI"), + ("BrowseAI", "BrowseAI"), + ("BrowserUse", "BrowserUse"), + ("ChartHop", "ChartHop"), + ("Cody", "Cody"), + ("Cursor", "Cursor"), + ("Decagon", "Decagon"), + ("Deepgram", "Deepgram"), + ("ElevenLabs", "ElevenLabs"), + ("Harvey", "Harvey"), + ("Hyperspell", "Hyperspell"), + ("Langfuse", "Langfuse"), + ("LingoDev", "LingoDev"), + ("M3ter", "M3ter"), + ("Maxio", "Maxio"), + ("Metorial", "Metorial"), + ("OpenRouter", "OpenRouter"), + ("TogetherAI", "TogetherAI"), + ("Vapi", "Vapi"), + ("Vespa", "Vespa"), + ("Writesonic", "Writesonic"), + ("Aiven", "Aiven"), + ("Aviator", "Aviator"), + ("Backblaze", "Backblaze"), + ("Baseten", "Baseten"), + ("Browserbase", "Browserbase"), + ("Cohere", "Cohere"), + ("DenoDeploy", "DenoDeploy"), + ("DigitalOcean", "DigitalOcean"), + ("E2B", "E2B"), + ("Fintoc", "Fintoc"), + ("Firecrawl", "Firecrawl"), + ("FireworksAI", "FireworksAI"), + ("FlyIo", "FlyIo"), + ("Groq", "Groq"), + ("GrowthBook", "GrowthBook"), + ("Gumloop", "Gumloop"), + ("Hatchet", "Hatchet"), + ("Helicone", "Helicone"), + ("Heroku", "Heroku"), + ("Hetzner", "Hetzner"), + ("HeyGen", "HeyGen"), + ("Infisical", "Infisical"), + ("Inngest", "Inngest"), + ("KapaAI", "KapaAI"), + ("Kernel", "Kernel"), + ("Koyeb", "Koyeb"), + ("LambdaLabs", "LambdaLabs"), + ("LangSmith", "LangSmith"), + ("Linode", "Linode"), + ("LlamaCloud", "LlamaCloud"), + ("Mem0", "Mem0"), + ("Metriport", "Metriport"), + ("Mintlify", "Mintlify"), + ("MistralAI", "MistralAI"), + ("Mono", "Mono"), + ("Netlify", "Netlify"), + ("Northflank", "Northflank"), + ("OpenAI", "OpenAI"), + ("Pinecone", "Pinecone"), + ("PlatformSh", "PlatformSh"), + ("PromptingCompany", "PromptingCompany"), + ("Qdrant", "Qdrant"), + ("Render", "Render"), + ("Replicate", "Replicate"), + ("RetellAI", "RetellAI"), + ("Roark", "Roark"), + ("RunPod", "RunPod"), + ("ScaleAI", "ScaleAI"), + ("Scaleway", "Scaleway"), + ("SigNoz", "SigNoz"), + ("Sim", "Sim"), + ("Skyvern", "Skyvern"), + ("Slash", "Slash"), + ("Synthesia", "Synthesia"), + ("Telli", "Telli"), + ("TerraApi", "TerraApi"), + ("TriggerDev", "TriggerDev"), + ("Turso", "Turso"), + ("Singular", "Singular"), + ("Swonkie", "Swonkie"), + ("TwelveLabs", "TwelveLabs"), + ("Twenty", "Twenty"), + ("Unstructured", "Unstructured"), + ("Upstash", "Upstash"), + ("Vellum", "Vellum"), + ("Vultr", "Vultr"), + ("Windmill", "Windmill"), + ("Zep", "Zep"), + ("Hex", "Hex"), + ("Sumsub", "Sumsub"), + ("GoogleChat", "GoogleChat"), + ("Kickscale", "Kickscale"), + ("Zellify", "Zellify"), + ("RudderStack", "RudderStack"), + ("DodoPayments", "DodoPayments"), + ("Salestrics", "Salestrics"), + ("Doppler", "Doppler"), + ("Usersnap", "Usersnap"), + ("Asknicely", "Asknicely"), + ("Featurebase", "Featurebase"), + ("Frill", "Frill"), + ("Bettermode", "Bettermode"), + ("Dynatrace", "Dynatrace"), + ("Honeycomb", "Honeycomb"), + ("SumoLogic", "SumoLogic"), + ("LogzIO", "LogzIO"), + ("Coralogix", "Coralogix"), + ("BetterStack", "BetterStack"), + ("Raygun", "Raygun"), + ("Honeybadger", "Honeybadger"), + ("Airbrake", "Airbrake"), + ("Appsignal", "Appsignal"), + ("Appdynamics", "Appdynamics"), + ("Instana", "Instana"), + ("SplunkObservabilityCloud", "SplunkObservabilityCloud"), + ("Uptimerobot", "Uptimerobot"), + ("Statuscake", "Statuscake"), + ("Tailscale", "Tailscale"), + ("Flagsmith", "Flagsmith"), + ("Xmatters", "Xmatters"), + ("Squadcast", "Squadcast"), + ("Zenduty", "Zenduty"), + ("Cronitor", "Cronitor"), + ("Jenkins", "Jenkins"), + ("Bitbucket", "Bitbucket"), + ("Gitea", "Gitea"), + ("Teamcity", "Teamcity"), + ("TravisCI", "TravisCI"), + ("Semaphore", "Semaphore"), + ("CircleciInsights", "CircleciInsights"), + ("OctopusDeploy", "OctopusDeploy"), + ("Sourcegraph", "Sourcegraph"), + ("Bitrise", "Bitrise"), + ("Gerrit", "Gerrit"), + ("TerraformCloud", "TerraformCloud"), + ("PulumiCloud", "PulumiCloud"), + ("Spacelift", "Spacelift"), + ("Railway", "Railway"), + ("Argocd", "Argocd"), + ("PrefectCloud", "PrefectCloud"), + ("DagsterCloud", "DagsterCloud"), + ("Env0", "Env0"), + ("Kubecost", "Kubecost"), + ("Snyk", "Snyk"), + ("Semgrep", "Semgrep"), + ("Veracode", "Veracode"), + ("Checkmarx", "Checkmarx"), + ("Gitguardian", "Gitguardian"), + ("QualysVmdr", "QualysVmdr"), + ("Rapid7Insightvm", "Rapid7Insightvm"), + ( + "TenableVulnerabilityManagement", + "TenableVulnerabilityManagement", + ), + ("Sentinelone", "Sentinelone"), + ("Lacework", "Lacework"), + ("OrcaSecurity", "OrcaSecurity"), + ("Drata", "Drata"), + ("Secureframe", "Secureframe"), + ("CiscoDuo", "CiscoDuo"), + ("Jumpcloud", "Jumpcloud"), + ("OnePassword", "OnePassword"), + ("Stytch", "Stytch"), + ("Sonarqube", "Sonarqube"), + ("Codecov", "Codecov"), + ("Coveralls", "Coveralls"), + ("Codacy", "Codacy"), + ("Deepsource", "Deepsource"), + ("Linearb", "Linearb"), + ("Jellyfish", "Jellyfish"), + ("Swarmia", "Swarmia"), + ("Packagist", "Packagist"), + ("Nuget", "Nuget"), + ("CratesIO", "CratesIO"), + ("SonatypeNexus", "SonatypeNexus"), + ("JfrogArtifactory", "JfrogArtifactory"), + ("Snowplow", "Snowplow"), + ("WeightsAndBiases", "WeightsAndBiases"), + ("MonteCarlo", "MonteCarlo"), + ("Metaplane", "Metaplane"), + ("Datahub", "Datahub"), + ("ClickhouseCloud", "ClickhouseCloud"), + ("ConfluentCloud", "ConfluentCloud"), + ("KongKonnect", "KongKonnect"), + ("Kandji", "Kandji"), + ("Automox", "Automox"), + ("Autumn", "Autumn"), + ("GetStream", "GetStream"), + ("Octolens", "Octolens"), + ("Kajabi", "Kajabi"), + ("Shopware", "Shopware"), + ("Dubsado", "Dubsado"), + ("Campfire", "Campfire"), + ("PromptWatch", "PromptWatch"), + ("Crisp", "Crisp"), + ("Kommo", "Kommo"), + ("Axiom", "Axiom"), + ("Plivo", "Plivo"), + ("DataForSEO", "DataForSEO"), + ("Sleekplan", "Sleekplan"), + ("AbTasty", "AbTasty"), + ("Ably", "Ably"), + ("AbnormalSecurity", "AbnormalSecurity"), + ("Acast", "Acast"), + ("Acculynx", "Acculynx"), + ("Actionstep", "Actionstep"), + ("Aftership", "Aftership"), + ("AhaIdeas", "AhaIdeas"), + ("AkamaiReporting", "AkamaiReporting"), + ("Alation", "Alation"), + ("Alegra", "Alegra"), + ("Allegro", "Allegro"), + ("AnodotCost", "AnodotCost"), + ("Anomalo", "Anomalo"), + ("Apaleo", "Apaleo"), + ("Apitally", "Apitally"), + ("AppStoreConnect", "AppStoreConnect"), + ("Appdirect", "Appdirect"), + ("Appfolio", "Appfolio"), + ("Arxiv", "Arxiv"), + ("Asaas", "Asaas"), + ("Astronomer", "Astronomer"), + ("Athenahealth", "Athenahealth"), + ("Atlan", "Atlan"), + ("AutodeskConstructionCloud", "AutodeskConstructionCloud"), + ("Avalara", "Avalara"), + ("AwsAthena", "AwsAthena"), + ("AwsBatch", "AwsBatch"), + ("AwsBudgets", "AwsBudgets"), + ("AwsCloudformation", "AwsCloudformation"), + ("AwsComputeOptimizer", "AwsComputeOptimizer"), + ("AwsConfig", "AwsConfig"), + ("AwsConnect", "AwsConnect"), + ("AwsCostAndUsageReport", "AwsCostAndUsageReport"), + ("AwsCostAnomalyDetection", "AwsCostAnomalyDetection"), + ("AwsCostExplorer", "AwsCostExplorer"), + ("AwsGlueDataCatalog", "AwsGlueDataCatalog"), + ("AwsGuardduty", "AwsGuardduty"), + ("AwsHealth", "AwsHealth"), + ("AwsIamAccessAnalyzer", "AwsIamAccessAnalyzer"), + ("AwsInspector", "AwsInspector"), + ("AwsMacie", "AwsMacie"), + ("AwsOrganizations", "AwsOrganizations"), + ("AwsRdsPerformanceInsights", "AwsRdsPerformanceInsights"), + ("AwsSagemaker", "AwsSagemaker"), + ("AwsSavingsPlans", "AwsSavingsPlans"), + ("AwsSecurityHub", "AwsSecurityHub"), + ("AwsSes", "AwsSes"), + ("AwsStepFunctions", "AwsStepFunctions"), + ("AwsSupport", "AwsSupport"), + ("AwsSystemsManager", "AwsSystemsManager"), + ("AwsTrustedAdvisor", "AwsTrustedAdvisor"), + ("AwsWaf", "AwsWaf"), + ("AwsXray", "AwsXray"), + ("AzureActivityLog", "AzureActivityLog"), + ("AzureAdvisor", "AzureAdvisor"), + ("AzureApiManagement", "AzureApiManagement"), + ("AzureApplicationInsights", "AzureApplicationInsights"), + ("AzureCostManagement", "AzureCostManagement"), + ("AzureDataExplorer", "AzureDataExplorer"), + ("AzureDataFactory", "AzureDataFactory"), + ("AzureLogAnalytics", "AzureLogAnalytics"), + ("AzureMonitorAlerts", "AzureMonitorAlerts"), + ("AzureMonitorMetrics", "AzureMonitorMetrics"), + ("AzureOpenaiUsage", "AzureOpenaiUsage"), + ("AzurePolicyInsights", "AzurePolicyInsights"), + ("AzureReservations", "AzureReservations"), + ("AzureResourceGraph", "AzureResourceGraph"), + ("AzureResourceHealth", "AzureResourceHealth"), + ("AzureServiceHealth", "AzureServiceHealth"), + ("AzureSynapse", "AzureSynapse"), + ("BackMarket", "BackMarket"), + ("Beehiiv", "Beehiiv"), + ("Bigeye", "Bigeye"), + ("BillCom", "BillCom"), + ("Billomat", "Billomat"), + ("BingWebmasterTools", "BingWebmasterTools"), + ("Bitwarden", "Bitwarden"), + ("BlackbaudRaisersEdgeNxt", "BlackbaudRaisersEdgeNxt"), + ("BlackboardLearn", "BlackboardLearn"), + ("Bling", "Bling"), + ("Bloomerang", "Bloomerang"), + ("Bluesky", "Bluesky"), + ("BolRetailer", "BolRetailer"), + ("Boulevard", "Boulevard"), + ("Buffer", "Buffer"), + ("Bugherd", "Bugherd"), + ("Buildium", "Buildium"), + ("Buttondown", "Buttondown"), + ("BuyMeACoffee", "BuyMeACoffee"), + ("Calendarific", "Calendarific"), + ("Calibre", "Calibre"), + ("CanvasLms", "CanvasLms"), + ("Captivate", "Captivate"), + ("Cashfree", "Cashfree"), + ("CastAi", "CastAi"), + ("Catchpoint", "Catchpoint"), + ("CdcOpenData", "CdcOpenData"), + ("Census", "Census"), + ("Checkly", "Checkly"), + ("CircleSo", "CircleSo"), + ("Classy", "Classy"), + ("Cleartax", "Cleartax"), + ("Clever", "Clever"), + ("Clevertap", "Clevertap"), + ("Cliniko", "Cliniko"), + ("Clio", "Clio"), + ("Clip", "Clip"), + ("Cloudability", "Cloudability"), + ("Cloudsmith", "Cloudsmith"), + ("Cloudzero", "Cloudzero"), + ("Clover", "Clover"), + ("Codemagic", "Codemagic"), + ("Codescene", "Codescene"), + ("Collibra", "Collibra"), + ("Companycam", "Companycam"), + ("Conekta", "Conekta"), + ("ContaAzul", "ContaAzul"), + ("Contentsquare", "Contentsquare"), + ("Cortex", "Cortex"), + ("Courier", "Courier"), + ("Crossref", "Crossref"), + ("CrowdstrikeFalcon", "CrowdstrikeFalcon"), + ("CubeCloud", "CubeCloud"), + ("D2lBrightspace", "D2lBrightspace"), + ("Dayforce", "Dayforce"), + ("Debugbear", "Debugbear"), + ("Descope", "Descope"), + ("Develocity", "Develocity"), + ("Dialpad", "Dialpad"), + ("Discord", "Discord"), + ("Discourse", "Discourse"), + ("Donorbox", "Donorbox"), + ("Doorloop", "Doorloop"), + ("Dovetail", "Dovetail"), + ("Drchrono", "Drchrono"), + ("Dynamics365BusinessCentral", "Dynamics365BusinessCentral"), + ("EcbDataPortal", "EcbDataPortal"), + ("Emarsys", "Emarsys"), + ("Embrace", "Embrace"), + ("Entsoe", "Entsoe"), + ("Eppo", "Eppo"), + ("Etsy", "Etsy"), + ("Eurostat", "Eurostat"), + ("Faire", "Faire"), + ("FarosAi", "FarosAi"), + ("Fieldpulse", "Fieldpulse"), + ("Fieldwire", "Fieldwire"), + ("Filevine", "Filevine"), + ("Finout", "Finout"), + ("Five9", "Five9"), + ("FlexeraCloudCost", "FlexeraCloudCost"), + ("Flutterwave", "Flutterwave"), + ("Fortnox", "Fortnox"), + ("Fourthwall", "Fourthwall"), + ("Fred", "Fred"), + ("Frontegg", "Frontegg"), + ("FusionAuth", "FusionAuth"), + ("G2", "G2"), + ("Gcore", "Gcore"), + ("GcpApigee", "GcpApigee"), + ("GcpArtifactRegistry", "GcpArtifactRegistry"), + ("GcpBigtable", "GcpBigtable"), + ("GcpChronicle", "GcpChronicle"), + ("GcpCloudAssetInventory", "GcpCloudAssetInventory"), + ("GcpCloudBilling", "GcpCloudBilling"), + ("GcpCloudBuild", "GcpCloudBuild"), + ("GcpCloudDeploy", "GcpCloudDeploy"), + ("GcpCloudDns", "GcpCloudDns"), + ("GcpCloudFunctions", "GcpCloudFunctions"), + ("GcpCloudLogging", "GcpCloudLogging"), + ("GcpCloudMonitoring", "GcpCloudMonitoring"), + ("GcpCloudRun", "GcpCloudRun"), + ("GcpCloudSpanner", "GcpCloudSpanner"), + ("GcpCloudSql", "GcpCloudSql"), + ("GcpCloudTrace", "GcpCloudTrace"), + ("GcpCloudWorkflows", "GcpCloudWorkflows"), + ("GcpComputeEngine", "GcpComputeEngine"), + ("GcpContainerAnalysis", "GcpContainerAnalysis"), + ("GcpDataflow", "GcpDataflow"), + ("GcpDataplex", "GcpDataplex"), + ("GcpDataproc", "GcpDataproc"), + ("GcpErrorReporting", "GcpErrorReporting"), + ("GcpGke", "GcpGke"), + ("GcpPubsub", "GcpPubsub"), + ("GcpRecaptchaEnterprise", "GcpRecaptchaEnterprise"), + ("GcpRecommender", "GcpRecommender"), + ("GcpSecurityCommandCenter", "GcpSecurityCommandCenter"), + ("Gdelt", "Gdelt"), + ("GenesysCloud", "GenesysCloud"), + ("Getdx", "Getdx"), + ("Ghost", "Ghost"), + ("Givebutter", "Givebutter"), + ("Gleif", "Gleif"), + ("GooglePlayConsole", "GooglePlayConsole"), + ("Guesty", "Guesty"), + ("Gumroad", "Gumroad"), + ("HarnessCcm", "HarnessCcm"), + ("HarnessSei", "HarnessSei"), + ("Harvest", "Harvest"), + ("Healthie", "Healthie"), + ("Hitpay", "Hitpay"), + ("Hivebrite", "Hivebrite"), + ("Holded", "Holded"), + ("Hostaway", "Hostaway"), + ("HousecallPro", "HousecallPro"), + ("Humanitec", "Humanitec"), + ("ImfData", "ImfData"), + ("Imperva", "Imperva"), + ("InfluxdbCloud", "InfluxdbCloud"), + ("Iyzico", "Iyzico"), + ("Jobtread", "Jobtread"), + ("Kameleoon", "Kameleoon"), + ("KauflandMarketplace", "KauflandMarketplace"), + ("Kestra", "Kestra"), + ("Kick", "Kick"), + ("Kinde", "Kinde"), + ("Kion", "Kion"), + ("Knowbe4", "Knowbe4"), + ("Komodor", "Komodor"), + ("Labelbox", "Labelbox"), + ("Lawmatics", "Lawmatics"), + ("Learnworlds", "Learnworlds"), + ("LexwareOffice", "LexwareOffice"), + ("Lightdash", "Lightdash"), + ("Lodgify", "Lodgify"), + ("Logicmonitor", "Logicmonitor"), + ("Logrocket", "Logrocket"), + ("LoopReturns", "LoopReturns"), + ("Mastodon", "Mastodon"), + ("Meetup", "Meetup"), + ("Memberful", "Memberful"), + ("MercadoPago", "MercadoPago"), + ("Meteostat", "Meteostat"), + ("Mews", "Mews"), + ("Mezmo", "Mezmo"), + ("Microsoft365UsageReports", "Microsoft365UsageReports"), + ("MicrosoftAdvertising", "MicrosoftAdvertising"), + ("MicrosoftClarity", "MicrosoftClarity"), + ("MicrosoftDefenderCloudApps", "MicrosoftDefenderCloudApps"), + ("MicrosoftDefenderEndpoint", "MicrosoftDefenderEndpoint"), + ("MicrosoftDefenderForCloud", "MicrosoftDefenderForCloud"), + ("MicrosoftIntune", "MicrosoftIntune"), + ("MicrosoftPurview", "MicrosoftPurview"), + ("MicrosoftPurviewAudit", "MicrosoftPurviewAudit"), + ("MicrosoftSentinel", "MicrosoftSentinel"), + ("MicrosoftTeamsCallRecords", "MicrosoftTeamsCallRecords"), + ("Midtrans", "Midtrans"), + ("MightyNetworks", "MightyNetworks"), + ("Mindbody", "Mindbody"), + ("Mirakl", "Mirakl"), + ("Moesif", "Moesif"), + ("Moneybird", "Moneybird"), + ("Moodle", "Moodle"), + ("Motherduck", "Motherduck"), + ("Mycase", "Mycase"), + ("NagerDate", "NagerDate"), + ("NeonCrm", "NeonCrm"), + ("Nexhealth", "Nexhealth"), + ("NoaaCdo", "NoaaCdo"), + ("Nobl9", "Nobl9"), + ("Nolt", "Nolt"), + ("Nops", "Nops"), + ("NpmRegistry", "NpmRegistry"), + ("Oecd", "Oecd"), + ("Okendo", "Okendo"), + ("Omni", "Omni"), + ("Onelogin", "Onelogin"), + ("OpenDental", "OpenDental"), + ("OpenMeteo", "OpenMeteo"), + ("Openalex", "Openalex"), + ("Opencorporates", "Opencorporates"), + ("Openfec", "Openfec"), + ("OpnPayments", "OpnPayments"), + ("Opslevel", "Opslevel"), + ("OttoMarket", "OttoMarket"), + ("Ownerrez", "Ownerrez"), + ("Pagbank", "Pagbank"), + ("Patreon", "Patreon"), + ("Pax8", "Pax8"), + ("Paychex", "Paychex"), + ("Paymob", "Paymob"), + ("Paymongo", "Paymongo"), + ("Phonepe", "Phonepe"), + ("Pike13", "Pike13"), + ("Pingone", "Pingone"), + ("PinterestOrganic", "PinterestOrganic"), + ("PlanningCenter", "PlanningCenter"), + ("PluralsightFlow", "PluralsightFlow"), + ("Podbean", "Podbean"), + ("Postscript", "Postscript"), + ("PowerBiAdmin", "PowerBiAdmin"), + ("Practicepanther", "Practicepanther"), + ("Preset", "Preset"), + ("Procore", "Procore"), + ("Productiv", "Productiv"), + ("ProofpointTap", "ProofpointTap"), + ("Propertyware", "Propertyware"), + ("Pubnub", "Pubnub"), + ("Quay", "Quay"), + ("Raken", "Raken"), + ("RedpandaCloud", "RedpandaCloud"), + ("RentManager", "RentManager"), + ("Reverb", "Reverb"), + ("RocketMatter", "RocketMatter"), + ("Rubygems", "Rubygems"), + ("Scalr", "Scalr"), + ("SecEdgar", "SecEdgar"), + ("SelectStar", "SelectStar"), + ("SemanticScholar", "SemanticScholar"), + ("Semrush", "Semrush"), + ("ServiceFusion", "ServiceFusion"), + ("Servicem8", "Servicem8"), + ("Servicetitan", "Servicetitan"), + ("Servicetrade", "Servicetrade"), + ("Sevdesk", "Sevdesk"), + ("Similarweb", "Similarweb"), + ("Simpro", "Simpro"), + ("Sinch", "Sinch"), + ("Singlestore", "Singlestore"), + ("Site24x7", "Site24x7"), + ("Sleuth", "Sleuth"), + ("Smartlook", "Smartlook"), + ("Smartrecruiters", "Smartrecruiters"), + ("Smokeball", "Smokeball"), + ("SodaCloud", "SodaCloud"), + ("Speedcurve", "Speedcurve"), + ("SpotIo", "SpotIo"), + ("Sprig", "Sprig"), + ("Sprinklr", "Sprinklr"), + ("SproutSocial", "SproutSocial"), + ("StackOverflowForTeams", "StackOverflowForTeams"), + ("Stockx", "Stockx"), + ("TackleIo", "TackleIo"), + ("Talkdesk", "Talkdesk"), + ("TeamupFitness", "TeamupFitness"), + ("Tebra", "Tebra"), + ("Telnyx", "Telnyx"), + ("Ternary", "Ternary"), + ("Thoughtspot", "Thoughtspot"), + ("Thousandeyes", "Thousandeyes"), + ("Threads", "Threads"), + ("TiktokShop", "TiktokShop"), + ("TinyErp", "TinyErp"), + ("Tinybird", "Tinybird"), + ("Tipalti", "Tipalti"), + ("Toast", "Toast"), + ("Torii", "Torii"), + ("Transistor", "Transistor"), + ("TrunkIo", "TrunkIo"), + ("Trustradius", "Trustradius"), + ("Twitch", "Twitch"), + ("TwoC2p", "TwoC2p"), + ("UkCompaniesHouse", "UkCompaniesHouse"), + ("UkOns", "UkOns"), + ("UnComtrade", "UnComtrade"), + ("UsBea", "UsBea"), + ("UsBls", "UsBls"), + ("UsEia", "UsEia"), + ("UsTreasuryFiscalData", "UsTreasuryFiscalData"), + ("Vanta", "Vanta"), + ("Vendr", "Vendr"), + ("Virtuous", "Virtuous"), + ("Vonage", "Vonage"), + ("WalmartMarketplace", "WalmartMarketplace"), + ("Waydev", "Waydev"), + ("Wayfair", "Wayfair"), + ("WhatsappBusinessManagement", "WhatsappBusinessManagement"), + ("WhoGho", "WhoGho"), + ("Whop", "Whop"), + ("Wiz", "Wiz"), + ("Wompi", "Wompi"), + ("Workiz", "Workiz"), + ("WorldBank", "WorldBank"), + ("Xendit", "Xendit"), + ("Yoco", "Yoco"), + ("ZalandoZdirect", "ZalandoZdirect"), + ("Zluri", "Zluri"), + ("Zylo", "Zylo"), + ("Tally", "Tally"), + ("Nuntly", "Nuntly"), + ("Vturb", "Vturb"), + ("Meltwater", "Meltwater"), + ("UserCom", "UserCom"), + ("Latitude", "Latitude"), + ("Workato", "Workato"), + ("SideShift", "SideShift"), + ("DuckLake", "DuckLake"), + ("Starburst", "Starburst"), + ("Easybill", "Easybill"), + ("Bexio", "Bexio"), + ("Umami", "Umami"), + ("Manychat", "Manychat"), + ("Kickstarter", "Kickstarter"), + ("Typesense", "Typesense"), + ("FirstPromoter", "FirstPromoter"), + ("Zero", "Zero"), + ("Inth", "Inth"), + ("BCMS", "BCMS"), + ("Convonite", "Convonite"), + ("Hookdeck", "Hookdeck"), + ("Billit", "Billit"), + ("Moxie", "Moxie"), + ("TripleWhale", "TripleWhale"), + ("Directus", "Directus"), + ("Clay", "Clay"), + ("TradableBits", "TradableBits"), + ("Swan", "Swan"), + ("Hyros", "Hyros"), + ("Odoo", "Odoo"), + ("Airbridge", "Airbridge"), + ("Snovio", "Snovio"), + ], + max_length=128, + ), + ), + migrations.AlterField( + model_name="pendingsourcecredential", + name="source_type", + field=models.CharField( + choices=[ + ("Ashby", "Ashby"), + ("Supabase", "Supabase"), + ("CustomerIO", "CustomerIO"), + ("Github", "Github"), + ("Stripe", "Stripe"), + ("Hubspot", "Hubspot"), + ("Postgres", "Postgres"), + ("Zendesk", "Zendesk"), + ("Snowflake", "Snowflake"), + ("Salesforce", "Salesforce"), + ("MySQL", "MySQL"), + ("MongoDB", "MongoDB"), + ("MSSQL", "MSSQL"), + ("Vitally", "Vitally"), + ("BigQuery", "BigQuery"), + ("Chargebee", "Chargebee"), + ("Clerk", "Clerk"), + ("GoogleAds", "GoogleAds"), + ("GoogleSearchConsole", "GoogleSearchConsole"), + ("TemporalIO", "TemporalIO"), + ("DoIt", "DoIt"), + ("GoogleSheets", "GoogleSheets"), + ("MetaAds", "MetaAds"), + ("Klaviyo", "Klaviyo"), + ("Mailchimp", "Mailchimp"), + ("Braze", "Braze"), + ("Mailjet", "Mailjet"), + ("Redshift", "Redshift"), + ("Polar", "Polar"), + ("RevenueCat", "RevenueCat"), + ("LinkedinAds", "LinkedinAds"), + ("RedditAds", "RedditAds"), + ("TikTokAds", "TikTokAds"), + ("BingAds", "BingAds"), + ("Shopify", "Shopify"), + ("Attio", "Attio"), + ("SnapchatAds", "SnapchatAds"), + ("Linear", "Linear"), + ("Intercom", "Intercom"), + ("Amplitude", "Amplitude"), + ("Mixpanel", "Mixpanel"), + ("Jira", "Jira"), + ("ActiveCampaign", "ActiveCampaign"), + ("Marketo", "Marketo"), + ("Adjust", "Adjust"), + ("AppsFlyer", "AppsFlyer"), + ("Freshdesk", "Freshdesk"), + ("GoogleAnalytics", "GoogleAnalytics"), + ("Pipedrive", "Pipedrive"), + ("SendGrid", "SendGrid"), + ("Slack", "Slack"), + ("PagerDuty", "PagerDuty"), + ("Asana", "Asana"), + ("Notion", "Notion"), + ("Airtable", "Airtable"), + ("Greenhouse", "Greenhouse"), + ("BambooHR", "BambooHR"), + ("Lever", "Lever"), + ("GitLab", "GitLab"), + ("Datadog", "Datadog"), + ("Sentry", "Sentry"), + ("Pendo", "Pendo"), + ("FullStory", "FullStory"), + ("AmazonAds", "AmazonAds"), + ("PinterestAds", "PinterestAds"), + ("AppleSearchAds", "AppleSearchAds"), + ("QuickBooks", "QuickBooks"), + ("Xero", "Xero"), + ("NetSuite", "NetSuite"), + ("WooCommerce", "WooCommerce"), + ("BigCommerce", "BigCommerce"), + ("PayPal", "PayPal"), + ("Square", "Square"), + ("Zoom", "Zoom"), + ("Trello", "Trello"), + ("Monday", "Monday"), + ("ClickUp", "ClickUp"), + ("Confluence", "Confluence"), + ("Recurly", "Recurly"), + ("SalesLoft", "SalesLoft"), + ("Outreach", "Outreach"), + ("Gong", "Gong"), + ("Calendly", "Calendly"), + ("Typeform", "Typeform"), + ("Iterable", "Iterable"), + ("ZohoCRM", "ZohoCRM"), + ("Close", "Close"), + ("Oracle", "Oracle"), + ("DynamoDB", "DynamoDB"), + ("Elasticsearch", "Elasticsearch"), + ("Kafka", "Kafka"), + ("LaunchDarkly", "LaunchDarkly"), + ("Braintree", "Braintree"), + ("Recharge", "Recharge"), + ("HelpScout", "HelpScout"), + ("Gorgias", "Gorgias"), + ("Instagram", "Instagram"), + ("YouTubeAnalytics", "YouTubeAnalytics"), + ("FacebookPages", "FacebookPages"), + ("TwitterAds", "TwitterAds"), + ("Workday", "Workday"), + ("ServiceNow", "ServiceNow"), + ("Pardot", "Pardot"), + ("Copper", "Copper"), + ("Front", "Front"), + ("ChartMogul", "ChartMogul"), + ("Zuora", "Zuora"), + ("Paddle", "Paddle"), + ("CircleCI", "CircleCI"), + ("CockroachDB", "CockroachDB"), + ("Firebase", "Firebase"), + ("AzureBlob", "AzureBlob"), + ("GoogleDrive", "GoogleDrive"), + ("OneDrive", "OneDrive"), + ("SharePoint", "SharePoint"), + ("Box", "Box"), + ("SFTP", "SFTP"), + ("MicrosoftTeams", "MicrosoftTeams"), + ("Aircall", "Aircall"), + ("Webflow", "Webflow"), + ("Okta", "Okta"), + ("Auth0", "Auth0"), + ("Productboard", "Productboard"), + ("Smartsheet", "Smartsheet"), + ("Wrike", "Wrike"), + ("Plaid", "Plaid"), + ("SurveyMonkey", "SurveyMonkey"), + ("Eventbrite", "Eventbrite"), + ("RingCentral", "RingCentral"), + ("Twilio", "Twilio"), + ("Freshsales", "Freshsales"), + ("Shortcut", "Shortcut"), + ("ConvertKit", "ConvertKit"), + ("Drip", "Drip"), + ("CampaignMonitor", "CampaignMonitor"), + ("MailerLite", "MailerLite"), + ("Omnisend", "Omnisend"), + ("Brevo", "Brevo"), + ("Postmark", "Postmark"), + ("Granola", "Granola"), + ("BuildBetter", "BuildBetter"), + ("Convex", "Convex"), + ("ClickHouse", "ClickHouse"), + ("Plain", "Plain"), + ("Resend", "Resend"), + ("PgAnalyze", "PgAnalyze"), + ("WorkOS", "WorkOS"), + ("AmazonS3", "AmazonS3"), + ("GoogleCloudStorage", "GoogleCloudStorage"), + ("Databricks", "Databricks"), + ("Dynamics365", "Dynamics365"), + ("SalesforceMarketingCloud", "SalesforceMarketingCloud"), + ("Db2", "Db2"), + ("Heap", "Heap"), + ("AdobeAnalytics", "AdobeAnalytics"), + ("Matomo", "Matomo"), + ("Optimizely", "Optimizely"), + ("Adyen", "Adyen"), + ("GoCardless", "GoCardless"), + ("Mollie", "Mollie"), + ("CheckoutCom", "CheckoutCom"), + ("Branch", "Branch"), + ("Criteo", "Criteo"), + ("Outbrain", "Outbrain"), + ("Taboola", "Taboola"), + ("AdRoll", "AdRoll"), + ("DisplayVideo360", "DisplayVideo360"), + ("GoogleAdManager", "GoogleAdManager"), + ("CampaignManager360", "CampaignManager360"), + ("SearchAds360", "SearchAds360"), + ("AdobeCommerce", "AdobeCommerce"), + ("AmazonSellingPartner", "AmazonSellingPartner"), + ("Ebay", "Ebay"), + ("Commercetools", "Commercetools"), + ("LightspeedRetail", "LightspeedRetail"), + ("Shipmail", "Shipmail"), + ("ShipStation", "ShipStation"), + ("ConstantContact", "ConstantContact"), + ("Mailgun", "Mailgun"), + ("Eloqua", "Eloqua"), + ("Sailthru", "Sailthru"), + ("Ortto", "Ortto"), + ("Attentive", "Attentive"), + ("Kustomer", "Kustomer"), + ("Dixa", "Dixa"), + ("Gladly", "Gladly"), + ("Qualtrics", "Qualtrics"), + ("AzureDevOps", "AzureDevOps"), + ("Rollbar", "Rollbar"), + ("Opsgenie", "Opsgenie"), + ("IncidentIo", "IncidentIo"), + ("Pingdom", "Pingdom"), + ("Cloudflare", "Cloudflare"), + ("CosmosDB", "CosmosDB"), + ("PlanetScale", "PlanetScale"), + ("SapHana", "SapHana"), + ("Rippling", "Rippling"), + ("HiBob", "HiBob"), + ("Personio", "Personio"), + ("Deel", "Deel"), + ("AdpWorkforceNow", "AdpWorkforceNow"), + ("Paylocity", "Paylocity"), + ("Gusto", "Gusto"), + ("CultureAmp", "CultureAmp"), + ("Lattice", "Lattice"), + ("SageIntacct", "SageIntacct"), + ("FreshBooks", "FreshBooks"), + ("Expensify", "Expensify"), + ("Ramp", "Ramp"), + ("Brex", "Brex"), + ("Coupa", "Coupa"), + ("SapConcur", "SapConcur"), + ("Apollo", "Apollo"), + ("Crunchbase", "Crunchbase"), + ("ZoomInfo", "ZoomInfo"), + ("Clari", "Clari"), + ("Chorus", "Chorus"), + ("Coda", "Coda"), + ("Guru", "Guru"), + ("Dropbox", "Dropbox"), + ("Docusign", "Docusign"), + ("PandaDoc", "PandaDoc"), + ("SapErp", "SapErp"), + ("SapSuccessFactors", "SapSuccessFactors"), + ("OracleEbs", "OracleEbs"), + ("OracleFusion", "OracleFusion"), + ("AmazonSNS", "AmazonSNS"), + ("AmazonEventBridge", "AmazonEventBridge"), + ("AmazonSQS", "AmazonSQS"), + ("AmazonKinesis", "AmazonKinesis"), + ("AmazonCloudWatch", "AmazonCloudWatch"), + ("OpenAIAds", "OpenAIAds"), + ("OneHundredMs", "OneHundredMs"), + ("SevenShifts", "SevenShifts"), + ("AcuityScheduling", "AcuityScheduling"), + ("AgileCRM", "AgileCRM"), + ("Aha", "Aha"), + ("Airbyte", "Airbyte"), + ("Akeneo", "Akeneo"), + ("Algolia", "Algolia"), + ("AlpacaBrokerAPI", "AlpacaBrokerAPI"), + ("ApifyDataset", "ApifyDataset"), + ("Appcues", "Appcues"), + ("Appfigures", "Appfigures"), + ("Appfollow", "Appfollow"), + ("Apptivo", "Apptivo"), + ("AssemblyAI", "AssemblyAI"), + ("Awin", "Awin"), + ("AwsCloudTrail", "AwsCloudTrail"), + ("AzureTableStorage", "AzureTableStorage"), + ("Babelforce", "Babelforce"), + ("Basecamp", "Basecamp"), + ("Beamer", "Beamer"), + ("BigMailer", "BigMailer"), + ("Bluetally", "Bluetally"), + ("BoldSign", "BoldSign"), + ("BreezyHR", "BreezyHR"), + ("Bugsnag", "Bugsnag"), + ("Buildkite", "Buildkite"), + ("Bunny", "Bunny"), + ("Buzzsprout", "Buzzsprout"), + ("CalCom", "CalCom"), + ("CallRail", "CallRail"), + ("Campayn", "Campayn"), + ("Canny", "Canny"), + ("CapsuleCRM", "CapsuleCRM"), + ("CaptainData", "CaptainData"), + ("CartCom", "CartCom"), + ("CastorEDC", "CastorEDC"), + ("Chameleon", "Chameleon"), + ("Chargedesk", "Chargedesk"), + ("Chargify", "Chargify"), + ("Chift", "Chift"), + ("Churnkey", "Churnkey"), + ("Cin7", "Cin7"), + ("CiscoMeraki", "CiscoMeraki"), + ("Clazar", "Clazar"), + ("Clockify", "Clockify"), + ("Clockodo", "Clockodo"), + ("Cloudbeds", "Cloudbeds"), + ("Coassemble", "Coassemble"), + ("Codefresh", "Codefresh"), + ("Concord", "Concord"), + ("ConfigCat", "ConfigCat"), + ("Couchbase", "Couchbase"), + ("Curve", "Curve"), + ("Customerly", "Customerly"), + ("Datascope", "Datascope"), + ("Dbt", "Dbt"), + ("Deputy", "Deputy"), + ("DevinAI", "DevinAI"), + ("Docuseal", "Docuseal"), + ("Dolibarr", "Dolibarr"), + ("Dremio", "Dremio"), + ("DropboxSign", "DropboxSign"), + ("Dwolla", "Dwolla"), + ("EConomic", "EConomic"), + ("Easypost", "Easypost"), + ("Easypromos", "Easypromos"), + ("Elasticemail", "Elasticemail"), + ("EmailOctopus", "EmailOctopus"), + ("EmploymentHero", "EmploymentHero"), + ("Encharge", "Encharge"), + ("Eventee", "Eventee"), + ("Eventzilla", "Eventzilla"), + ("Everhour", "Everhour"), + ("EZOfficeInventory", "EZOfficeInventory"), + ("Factorial", "Factorial"), + ("Fastbill", "Fastbill"), + ("Fastly", "Fastly"), + ("Fauna", "Fauna"), + ("Feishu", "Feishu"), + ("Fillout", "Fillout"), + ("Finage", "Finage"), + ("Firebolt", "Firebolt"), + ("FireHydrant", "FireHydrant"), + ("Fleetio", "Fleetio"), + ("Flexmail", "Flexmail"), + ("Flexport", "Flexport"), + ("FloatApp", "FloatApp"), + ("Flowlu", "Flowlu"), + ("Formbricks", "Formbricks"), + ("FreeAgent", "FreeAgent"), + ("Freightview", "Freightview"), + ("Freshcaller", "Freshcaller"), + ("Freshchat", "Freshchat"), + ("Freshservice", "Freshservice"), + ("Fulcrum", "Fulcrum"), + ("GainsightPx", "GainsightPx"), + ("GitBook", "GitBook"), + ("Glassfrog", "Glassfrog"), + ("Goldcast", "Goldcast"), + ("GoLogin", "GoLogin"), + ("Grafana", "Grafana"), + ("GreytHr", "GreytHr"), + ("Gridly", "Gridly"), + ("Harness", "Harness"), + ("Height", "Height"), + ("Hellobaton", "Hellobaton"), + ("HighLevel", "HighLevel"), + ("HoorayHR", "HoorayHR"), + ("Hubplanner", "Hubplanner"), + ("Humanitix", "Humanitix"), + ("Huntr", "Huntr"), + ("Inflowinventory", "Inflowinventory"), + ("InforNexus", "InforNexus"), + ("Insightful", "Insightful"), + ("Insightly", "Insightly"), + ("Instantly", "Instantly"), + ("Instatus", "Instatus"), + ("Intruder", "Intruder"), + ("Invoiced", "Invoiced"), + ("Invoiceninja", "Invoiceninja"), + ("JamfPro", "JamfPro"), + ("JobNimbus", "JobNimbus"), + ("Jotform", "Jotform"), + ("JudgeMeReviews", "JudgeMeReviews"), + ("JustCall", "JustCall"), + ("JustSift", "JustSift"), + ("K6Cloud", "K6Cloud"), + ("Katana", "Katana"), + ("Keka", "Keka"), + ("Kisi", "Kisi"), + ("Kissmetrics", "Kissmetrics"), + ("Klarna", "Klarna"), + ("Klaus", "Klaus"), + ("Lago", "Lago"), + ("Leadfeeder", "Leadfeeder"), + ("Lemlist", "Lemlist"), + ("LessAnnoyingCRM", "LessAnnoyingCRM"), + ("LinkedinPages", "LinkedinPages"), + ("Linkrunner", "Linkrunner"), + ("Linnworks", "Linnworks"), + ("Lob", "Lob"), + ("Lokalise", "Lokalise"), + ("Looker", "Looker"), + ("Luma", "Luma"), + ("MailerSend", "MailerSend"), + ("Mailosaur", "Mailosaur"), + ("Mailtrap", "Mailtrap"), + ("Mantle", "Mantle"), + ("Mention", "Mention"), + ("MercadoAds", "MercadoAds"), + ("Merge", "Merge"), + ("Metabase", "Metabase"), + ("Metricool", "Metricool"), + ("MicrosoftDataverse", "MicrosoftDataverse"), + ("MicrosoftEntraId", "MicrosoftEntraId"), + ("MicrosoftLists", "MicrosoftLists"), + ("Miro", "Miro"), + ("Missive", "Missive"), + ("MixMax", "MixMax"), + ("Mode", "Mode"), + ("Mux", "Mux"), + ("MyHours", "MyHours"), + ("N8n", "N8n"), + ("Navan", "Navan"), + ("NebiusAI", "NebiusAI"), + ("Nexiopay", "Nexiopay"), + ("NinjaOneRMM", "NinjaOneRMM"), + ("NoCRM", "NoCRM"), + ("NorthpassLMS", "NorthpassLMS"), + ("Nutshell", "Nutshell"), + ("Nylas", "Nylas"), + ("Oncehub", "Oncehub"), + ("Onepagecrm", "Onepagecrm"), + ("OneSignal", "OneSignal"), + ("Onfleet", "Onfleet"), + ("OpinionStage", "OpinionStage"), + ("OPUSWatch", "OPUSWatch"), + ("Orb", "Orb"), + ("Orbit", "Orbit"), + ("Oura", "Oura"), + ("Oveit", "Oveit"), + ("PabblySubscriptionsBilling", "PabblySubscriptionsBilling"), + ("Paperform", "Paperform"), + ("Papersign", "Papersign"), + ("Partnerize", "Partnerize"), + ("PartnerStack", "PartnerStack"), + ("PayFit", "PayFit"), + ("Paystack", "Paystack"), + ("Pennylane", "Pennylane"), + ("Perk", "Perk"), + ("PersistIq", "PersistIq"), + ("Persona", "Persona"), + ("Phyllo", "Phyllo"), + ("Picqer", "Picqer"), + ("Pipeliner", "Pipeliner"), + ("PivotalTracker", "PivotalTracker"), + ("Piwik", "Piwik"), + ("Planhat", "Planhat"), + ("Plausible", "Plausible"), + ("Poplar", "Poplar"), + ("PrestaShop", "PrestaShop"), + ("Pretix", "Pretix"), + ("Primetric", "Primetric"), + ("Printavo", "Printavo"), + ("Printify", "Printify"), + ("Productive", "Productive"), + ("Pylon", "Pylon"), + ("Qonto", "Qonto"), + ("Qualaroo", "Qualaroo"), + ("Railz", "Railz"), + ("RDStationMarketing", "RDStationMarketing"), + ("Recruitee", "Recruitee"), + ("Reddit", "Reddit"), + ("ReferralHero", "ReferralHero"), + ("RentCast", "RentCast"), + ("Repairshopr", "Repairshopr"), + ("ReplyIo", "ReplyIo"), + ("RetailExpress", "RetailExpress"), + ("Retently", "Retently"), + ("RevolutMerchant", "RevolutMerchant"), + ("RocketChat", "RocketChat"), + ("Rocketlane", "Rocketlane"), + ("Rootly", "Rootly"), + ("Ruddr", "Ruddr"), + ("SafetyCulture", "SafetyCulture"), + ("SageHR", "SageHR"), + ("Salesflare", "Salesflare"), + ("SAPFieldglass", "SAPFieldglass"), + ("SavvyCal", "SavvyCal"), + ("Secoda", "Secoda"), + ("Segment", "Segment"), + ("Sendowl", "Sendowl"), + ("SendPulse", "SendPulse"), + ("Senseforce", "Senseforce"), + ("Serpstat", "Serpstat"), + ("Sharetribe", "Sharetribe"), + ("Shippo", "Shippo"), + ("ShopWired", "ShopWired"), + ("Shortio", "Shortio"), + ("Shutterstock", "Shutterstock"), + ("SigmaComputing", "SigmaComputing"), + ("SignNow", "SignNow"), + ("SimpleCast", "SimpleCast"), + ("Simplesat", "Simplesat"), + ("Smaily", "Smaily"), + ("SmartEngage", "SmartEngage"), + ("Smartreach", "Smartreach"), + ("Smartwaiver", "Smartwaiver"), + ("SolarwindsServiceDesk", "SolarwindsServiceDesk"), + ("SonarCloud", "SonarCloud"), + ("SparkPost", "SparkPost"), + ("SplitIo", "SplitIo"), + ("SpotifyAds", "SpotifyAds"), + ("SpotlerCRM", "SpotlerCRM"), + ("Squarespace", "Squarespace"), + ("Statsig", "Statsig"), + ("Statuspage", "Statuspage"), + ("Stigg", "Stigg"), + ("Strava", "Strava"), + ("SurveySparrow", "SurveySparrow"), + ("Survicate", "Survicate"), + ("Svix", "Svix"), + ("Systeme", "Systeme"), + ("Tavus", "Tavus"), + ("Teamtailor", "Teamtailor"), + ("Teamwork", "Teamwork"), + ("Tempo", "Tempo"), + ("Testrail", "Testrail"), + ("Thinkific", "Thinkific"), + ("ThinkificCourses", "ThinkificCourses"), + ("ThriveLearning", "ThriveLearning"), + ("Ticketmaster", "Ticketmaster"), + ("TicketTailor", "TicketTailor"), + ("TickTick", "TickTick"), + ("Timely", "Timely"), + ("Tinyemail", "Tinyemail"), + ("Todoist", "Todoist"), + ("Toggl", "Toggl"), + ("TrackPMS", "TrackPMS"), + ("Tremendous", "Tremendous"), + ("TrustPilot", "TrustPilot"), + ("Twitter", "Twitter"), + ("TyntecSMS", "TyntecSMS"), + ("Unleash", "Unleash"), + ("UpPromote", "UpPromote"), + ("Uptick", "Uptick"), + ("Uservoice", "Uservoice"), + ("Vantage", "Vantage"), + ("Veeqo", "Veeqo"), + ("Vercel", "Vercel"), + ("VismaEconomic", "VismaEconomic"), + ("VWO", "VWO"), + ("Waiteraid", "Waiteraid"), + ("Wasabi", "Wasabi"), + ("WhenIWork", "WhenIWork"), + ("Wordpress", "Wordpress"), + ("Workable", "Workable"), + ("Workflowmax", "Workflowmax"), + ("Workramp", "Workramp"), + ("Wufoo", "Wufoo"), + ("Xsolla", "Xsolla"), + ("YandexMetrica", "YandexMetrica"), + ("Yotpo", "Yotpo"), + ("Ynab", "Ynab"), + ("Younium", "Younium"), + ("YouSign", "YouSign"), + ("YoutubeData", "YoutubeData"), + ("ZapierSupportedStorage", "ZapierSupportedStorage"), + ("ZapSign", "ZapSign"), + ("ZendeskSell", "ZendeskSell"), + ("ZendeskSunshine", "ZendeskSunshine"), + ("Zenefits", "Zenefits"), + ("Zenloop", "Zenloop"), + ("ZohoAnalytics", "ZohoAnalytics"), + ("ZohoBigin", "ZohoBigin"), + ("ZohoBilling", "ZohoBilling"), + ("ZohoBooks", "ZohoBooks"), + ("ZohoCampaign", "ZohoCampaign"), + ("ZohoDesk", "ZohoDesk"), + ("ZohoExpense", "ZohoExpense"), + ("ZohoInventory", "ZohoInventory"), + ("ZohoInvoice", "ZohoInvoice"), + ("ZonkaFeedback", "ZonkaFeedback"), + ("AlphaVantage", "AlphaVantage"), + ("Aviationstack", "Aviationstack"), + ("Bitly", "Bitly"), + ("Blogger", "Blogger"), + ("Breezometer", "Breezometer"), + ("CareQualityCommission", "CareQualityCommission"), + ("Cimis", "Cimis"), + ("CoinApi", "CoinApi"), + ("CoinGecko", "CoinGecko"), + ("CoinMarketCap", "CoinMarketCap"), + ("DingConnect", "DingConnect"), + ("Dockerhub", "Dockerhub"), + ("ExchangeRatesApi", "ExchangeRatesApi"), + ("FinancialModelling", "FinancialModelling"), + ("Finnhub", "Finnhub"), + ("Finnworlds", "Finnworlds"), + ("Giphy", "Giphy"), + ("Gmail", "Gmail"), + ("GNews", "GNews"), + ("GoogleCalendar", "GoogleCalendar"), + ("GoogleClassroom", "GoogleClassroom"), + ("GoogleDirectory", "GoogleDirectory"), + ("GoogleForms", "GoogleForms"), + ("GooglePageSpeedInsights", "GooglePageSpeedInsights"), + ("GoogleTasks", "GoogleTasks"), + ("GoogleWebfonts", "GoogleWebfonts"), + ("GoogleWorkspaceAdminReports", "GoogleWorkspaceAdminReports"), + ("HuggingFace", "HuggingFace"), + ("IlluminaBasespace", "IlluminaBasespace"), + ("Imagga", "Imagga"), + ("Interzoid", "Interzoid"), + ("IP2Whois", "IP2Whois"), + ("KYVE", "KYVE"), + ("Marketstack", "Marketstack"), + ("Mendeley", "Mendeley"), + ("Nasa", "Nasa"), + ("NewYorkTimes", "NewYorkTimes"), + ("NewsApi", "NewsApi"), + ("NewsData", "NewsData"), + ("OpenDataDc", "OpenDataDc"), + ("OpenExchangeRates", "OpenExchangeRates"), + ("OpenAQ", "OpenAQ"), + ("OpenFDA", "OpenFDA"), + ("OpenWeather", "OpenWeather"), + ("Outlook", "Outlook"), + ("Perigon", "Perigon"), + ("Pexels", "Pexels"), + ("Pocket", "Pocket"), + ("Polygon", "Polygon"), + ("PyPI", "PyPI"), + ("Recreation", "Recreation"), + ("RKICovid", "RKICovid"), + ("Rss", "Rss"), + ("SimFin", "SimFin"), + ("StockData", "StockData"), + ("Guardian", "Guardian"), + ("TMDb", "TMDb"), + ("TVMaze", "TVMaze"), + ("TwelveData", "TwelveData"), + ("Ubidots", "Ubidots"), + ("USCensus", "USCensus"), + ("Watchmode", "Watchmode"), + ("WikipediaPageviews", "WikipediaPageviews"), + ("YahooFinance", "YahooFinance"), + ("Clarifai", "Clarifai"), + ("Adapty", "Adapty"), + ("Braintrust", "Braintrust"), + ("StreamElements", "StreamElements"), + ("Streamlabs", "Streamlabs"), + ("Datorama", "Datorama"), + ("Ahrefs", "Ahrefs"), + ("Lightfield", "Lightfield"), + ("Appstack", "Appstack"), + ("Razorpay", "Razorpay"), + ("Neon", "Neon"), + ("NewRelic", "NewRelic"), + ("Custom", "Custom"), + ("Tile38", "Tile38"), + ("Chatwoot", "Chatwoot"), + ("Sanity", "Sanity"), + ("Metronome", "Metronome"), + ("Jobber", "Jobber"), + ("Knock", "Knock"), + ("Leexi", "Leexi"), + ("RB2B", "RB2B"), + ("Superwall", "Superwall"), + ("Liana", "Liana"), + ("TawkTo", "TawkTo"), + ("Hightouch", "Hightouch"), + ("LemonSqueezy", "LemonSqueezy"), + ("Ikas", "Ikas"), + ("Talkwalker", "Talkwalker"), + ("NextdoorAds", "NextdoorAds"), + ("AppLovin", "AppLovin"), + ("Baserow", "Baserow"), + ("Plunk", "Plunk"), + ("Dub", "Dub"), + ("AirOps", "AirOps"), + ("Podium", "Podium"), + ("Loops", "Loops"), + ("Redis", "Redis"), + ("Mercury", "Mercury"), + ("Gojiberry", "Gojiberry"), + ("Teachable", "Teachable"), + ("PeecAI", "PeecAI"), + ("Healthchecks", "Healthchecks"), + ("Impact", "Impact"), + ("AikidoSecurity", "AikidoSecurity"), + ("Alguna", "Alguna"), + ("Anthropic", "Anthropic"), + ("Appwrite", "Appwrite"), + ("BlandAI", "BlandAI"), + ("BrowseAI", "BrowseAI"), + ("BrowserUse", "BrowserUse"), + ("ChartHop", "ChartHop"), + ("Cody", "Cody"), + ("Cursor", "Cursor"), + ("Decagon", "Decagon"), + ("Deepgram", "Deepgram"), + ("ElevenLabs", "ElevenLabs"), + ("Harvey", "Harvey"), + ("Hyperspell", "Hyperspell"), + ("Langfuse", "Langfuse"), + ("LingoDev", "LingoDev"), + ("M3ter", "M3ter"), + ("Maxio", "Maxio"), + ("Metorial", "Metorial"), + ("OpenRouter", "OpenRouter"), + ("TogetherAI", "TogetherAI"), + ("Vapi", "Vapi"), + ("Vespa", "Vespa"), + ("Writesonic", "Writesonic"), + ("Aiven", "Aiven"), + ("Aviator", "Aviator"), + ("Backblaze", "Backblaze"), + ("Baseten", "Baseten"), + ("Browserbase", "Browserbase"), + ("Cohere", "Cohere"), + ("DenoDeploy", "DenoDeploy"), + ("DigitalOcean", "DigitalOcean"), + ("E2B", "E2B"), + ("Fintoc", "Fintoc"), + ("Firecrawl", "Firecrawl"), + ("FireworksAI", "FireworksAI"), + ("FlyIo", "FlyIo"), + ("Groq", "Groq"), + ("GrowthBook", "GrowthBook"), + ("Gumloop", "Gumloop"), + ("Hatchet", "Hatchet"), + ("Helicone", "Helicone"), + ("Heroku", "Heroku"), + ("Hetzner", "Hetzner"), + ("HeyGen", "HeyGen"), + ("Infisical", "Infisical"), + ("Inngest", "Inngest"), + ("KapaAI", "KapaAI"), + ("Kernel", "Kernel"), + ("Koyeb", "Koyeb"), + ("LambdaLabs", "LambdaLabs"), + ("LangSmith", "LangSmith"), + ("Linode", "Linode"), + ("LlamaCloud", "LlamaCloud"), + ("Mem0", "Mem0"), + ("Metriport", "Metriport"), + ("Mintlify", "Mintlify"), + ("MistralAI", "MistralAI"), + ("Mono", "Mono"), + ("Netlify", "Netlify"), + ("Northflank", "Northflank"), + ("OpenAI", "OpenAI"), + ("Pinecone", "Pinecone"), + ("PlatformSh", "PlatformSh"), + ("PromptingCompany", "PromptingCompany"), + ("Qdrant", "Qdrant"), + ("Render", "Render"), + ("Replicate", "Replicate"), + ("RetellAI", "RetellAI"), + ("Roark", "Roark"), + ("RunPod", "RunPod"), + ("ScaleAI", "ScaleAI"), + ("Scaleway", "Scaleway"), + ("SigNoz", "SigNoz"), + ("Sim", "Sim"), + ("Skyvern", "Skyvern"), + ("Slash", "Slash"), + ("Synthesia", "Synthesia"), + ("Telli", "Telli"), + ("TerraApi", "TerraApi"), + ("TriggerDev", "TriggerDev"), + ("Turso", "Turso"), + ("Singular", "Singular"), + ("Swonkie", "Swonkie"), + ("TwelveLabs", "TwelveLabs"), + ("Twenty", "Twenty"), + ("Unstructured", "Unstructured"), + ("Upstash", "Upstash"), + ("Vellum", "Vellum"), + ("Vultr", "Vultr"), + ("Windmill", "Windmill"), + ("Zep", "Zep"), + ("Hex", "Hex"), + ("Sumsub", "Sumsub"), + ("GoogleChat", "GoogleChat"), + ("Kickscale", "Kickscale"), + ("Zellify", "Zellify"), + ("RudderStack", "RudderStack"), + ("DodoPayments", "DodoPayments"), + ("Salestrics", "Salestrics"), + ("Doppler", "Doppler"), + ("Usersnap", "Usersnap"), + ("Asknicely", "Asknicely"), + ("Featurebase", "Featurebase"), + ("Frill", "Frill"), + ("Bettermode", "Bettermode"), + ("Dynatrace", "Dynatrace"), + ("Honeycomb", "Honeycomb"), + ("SumoLogic", "SumoLogic"), + ("LogzIO", "LogzIO"), + ("Coralogix", "Coralogix"), + ("BetterStack", "BetterStack"), + ("Raygun", "Raygun"), + ("Honeybadger", "Honeybadger"), + ("Airbrake", "Airbrake"), + ("Appsignal", "Appsignal"), + ("Appdynamics", "Appdynamics"), + ("Instana", "Instana"), + ("SplunkObservabilityCloud", "SplunkObservabilityCloud"), + ("Uptimerobot", "Uptimerobot"), + ("Statuscake", "Statuscake"), + ("Tailscale", "Tailscale"), + ("Flagsmith", "Flagsmith"), + ("Xmatters", "Xmatters"), + ("Squadcast", "Squadcast"), + ("Zenduty", "Zenduty"), + ("Cronitor", "Cronitor"), + ("Jenkins", "Jenkins"), + ("Bitbucket", "Bitbucket"), + ("Gitea", "Gitea"), + ("Teamcity", "Teamcity"), + ("TravisCI", "TravisCI"), + ("Semaphore", "Semaphore"), + ("CircleciInsights", "CircleciInsights"), + ("OctopusDeploy", "OctopusDeploy"), + ("Sourcegraph", "Sourcegraph"), + ("Bitrise", "Bitrise"), + ("Gerrit", "Gerrit"), + ("TerraformCloud", "TerraformCloud"), + ("PulumiCloud", "PulumiCloud"), + ("Spacelift", "Spacelift"), + ("Railway", "Railway"), + ("Argocd", "Argocd"), + ("PrefectCloud", "PrefectCloud"), + ("DagsterCloud", "DagsterCloud"), + ("Env0", "Env0"), + ("Kubecost", "Kubecost"), + ("Snyk", "Snyk"), + ("Semgrep", "Semgrep"), + ("Veracode", "Veracode"), + ("Checkmarx", "Checkmarx"), + ("Gitguardian", "Gitguardian"), + ("QualysVmdr", "QualysVmdr"), + ("Rapid7Insightvm", "Rapid7Insightvm"), + ( + "TenableVulnerabilityManagement", + "TenableVulnerabilityManagement", + ), + ("Sentinelone", "Sentinelone"), + ("Lacework", "Lacework"), + ("OrcaSecurity", "OrcaSecurity"), + ("Drata", "Drata"), + ("Secureframe", "Secureframe"), + ("CiscoDuo", "CiscoDuo"), + ("Jumpcloud", "Jumpcloud"), + ("OnePassword", "OnePassword"), + ("Stytch", "Stytch"), + ("Sonarqube", "Sonarqube"), + ("Codecov", "Codecov"), + ("Coveralls", "Coveralls"), + ("Codacy", "Codacy"), + ("Deepsource", "Deepsource"), + ("Linearb", "Linearb"), + ("Jellyfish", "Jellyfish"), + ("Swarmia", "Swarmia"), + ("Packagist", "Packagist"), + ("Nuget", "Nuget"), + ("CratesIO", "CratesIO"), + ("SonatypeNexus", "SonatypeNexus"), + ("JfrogArtifactory", "JfrogArtifactory"), + ("Snowplow", "Snowplow"), + ("WeightsAndBiases", "WeightsAndBiases"), + ("MonteCarlo", "MonteCarlo"), + ("Metaplane", "Metaplane"), + ("Datahub", "Datahub"), + ("ClickhouseCloud", "ClickhouseCloud"), + ("ConfluentCloud", "ConfluentCloud"), + ("KongKonnect", "KongKonnect"), + ("Kandji", "Kandji"), + ("Automox", "Automox"), + ("Autumn", "Autumn"), + ("GetStream", "GetStream"), + ("Octolens", "Octolens"), + ("Kajabi", "Kajabi"), + ("Shopware", "Shopware"), + ("Dubsado", "Dubsado"), + ("Campfire", "Campfire"), + ("PromptWatch", "PromptWatch"), + ("Crisp", "Crisp"), + ("Kommo", "Kommo"), + ("Axiom", "Axiom"), + ("Plivo", "Plivo"), + ("DataForSEO", "DataForSEO"), + ("Sleekplan", "Sleekplan"), + ("AbTasty", "AbTasty"), + ("Ably", "Ably"), + ("AbnormalSecurity", "AbnormalSecurity"), + ("Acast", "Acast"), + ("Acculynx", "Acculynx"), + ("Actionstep", "Actionstep"), + ("Aftership", "Aftership"), + ("AhaIdeas", "AhaIdeas"), + ("AkamaiReporting", "AkamaiReporting"), + ("Alation", "Alation"), + ("Alegra", "Alegra"), + ("Allegro", "Allegro"), + ("AnodotCost", "AnodotCost"), + ("Anomalo", "Anomalo"), + ("Apaleo", "Apaleo"), + ("Apitally", "Apitally"), + ("AppStoreConnect", "AppStoreConnect"), + ("Appdirect", "Appdirect"), + ("Appfolio", "Appfolio"), + ("Arxiv", "Arxiv"), + ("Asaas", "Asaas"), + ("Astronomer", "Astronomer"), + ("Athenahealth", "Athenahealth"), + ("Atlan", "Atlan"), + ("AutodeskConstructionCloud", "AutodeskConstructionCloud"), + ("Avalara", "Avalara"), + ("AwsAthena", "AwsAthena"), + ("AwsBatch", "AwsBatch"), + ("AwsBudgets", "AwsBudgets"), + ("AwsCloudformation", "AwsCloudformation"), + ("AwsComputeOptimizer", "AwsComputeOptimizer"), + ("AwsConfig", "AwsConfig"), + ("AwsConnect", "AwsConnect"), + ("AwsCostAndUsageReport", "AwsCostAndUsageReport"), + ("AwsCostAnomalyDetection", "AwsCostAnomalyDetection"), + ("AwsCostExplorer", "AwsCostExplorer"), + ("AwsGlueDataCatalog", "AwsGlueDataCatalog"), + ("AwsGuardduty", "AwsGuardduty"), + ("AwsHealth", "AwsHealth"), + ("AwsIamAccessAnalyzer", "AwsIamAccessAnalyzer"), + ("AwsInspector", "AwsInspector"), + ("AwsMacie", "AwsMacie"), + ("AwsOrganizations", "AwsOrganizations"), + ("AwsRdsPerformanceInsights", "AwsRdsPerformanceInsights"), + ("AwsSagemaker", "AwsSagemaker"), + ("AwsSavingsPlans", "AwsSavingsPlans"), + ("AwsSecurityHub", "AwsSecurityHub"), + ("AwsSes", "AwsSes"), + ("AwsStepFunctions", "AwsStepFunctions"), + ("AwsSupport", "AwsSupport"), + ("AwsSystemsManager", "AwsSystemsManager"), + ("AwsTrustedAdvisor", "AwsTrustedAdvisor"), + ("AwsWaf", "AwsWaf"), + ("AwsXray", "AwsXray"), + ("AzureActivityLog", "AzureActivityLog"), + ("AzureAdvisor", "AzureAdvisor"), + ("AzureApiManagement", "AzureApiManagement"), + ("AzureApplicationInsights", "AzureApplicationInsights"), + ("AzureCostManagement", "AzureCostManagement"), + ("AzureDataExplorer", "AzureDataExplorer"), + ("AzureDataFactory", "AzureDataFactory"), + ("AzureLogAnalytics", "AzureLogAnalytics"), + ("AzureMonitorAlerts", "AzureMonitorAlerts"), + ("AzureMonitorMetrics", "AzureMonitorMetrics"), + ("AzureOpenaiUsage", "AzureOpenaiUsage"), + ("AzurePolicyInsights", "AzurePolicyInsights"), + ("AzureReservations", "AzureReservations"), + ("AzureResourceGraph", "AzureResourceGraph"), + ("AzureResourceHealth", "AzureResourceHealth"), + ("AzureServiceHealth", "AzureServiceHealth"), + ("AzureSynapse", "AzureSynapse"), + ("BackMarket", "BackMarket"), + ("Beehiiv", "Beehiiv"), + ("Bigeye", "Bigeye"), + ("BillCom", "BillCom"), + ("Billomat", "Billomat"), + ("BingWebmasterTools", "BingWebmasterTools"), + ("Bitwarden", "Bitwarden"), + ("BlackbaudRaisersEdgeNxt", "BlackbaudRaisersEdgeNxt"), + ("BlackboardLearn", "BlackboardLearn"), + ("Bling", "Bling"), + ("Bloomerang", "Bloomerang"), + ("Bluesky", "Bluesky"), + ("BolRetailer", "BolRetailer"), + ("Boulevard", "Boulevard"), + ("Buffer", "Buffer"), + ("Bugherd", "Bugherd"), + ("Buildium", "Buildium"), + ("Buttondown", "Buttondown"), + ("BuyMeACoffee", "BuyMeACoffee"), + ("Calendarific", "Calendarific"), + ("Calibre", "Calibre"), + ("CanvasLms", "CanvasLms"), + ("Captivate", "Captivate"), + ("Cashfree", "Cashfree"), + ("CastAi", "CastAi"), + ("Catchpoint", "Catchpoint"), + ("CdcOpenData", "CdcOpenData"), + ("Census", "Census"), + ("Checkly", "Checkly"), + ("CircleSo", "CircleSo"), + ("Classy", "Classy"), + ("Cleartax", "Cleartax"), + ("Clever", "Clever"), + ("Clevertap", "Clevertap"), + ("Cliniko", "Cliniko"), + ("Clio", "Clio"), + ("Clip", "Clip"), + ("Cloudability", "Cloudability"), + ("Cloudsmith", "Cloudsmith"), + ("Cloudzero", "Cloudzero"), + ("Clover", "Clover"), + ("Codemagic", "Codemagic"), + ("Codescene", "Codescene"), + ("Collibra", "Collibra"), + ("Companycam", "Companycam"), + ("Conekta", "Conekta"), + ("ContaAzul", "ContaAzul"), + ("Contentsquare", "Contentsquare"), + ("Cortex", "Cortex"), + ("Courier", "Courier"), + ("Crossref", "Crossref"), + ("CrowdstrikeFalcon", "CrowdstrikeFalcon"), + ("CubeCloud", "CubeCloud"), + ("D2lBrightspace", "D2lBrightspace"), + ("Dayforce", "Dayforce"), + ("Debugbear", "Debugbear"), + ("Descope", "Descope"), + ("Develocity", "Develocity"), + ("Dialpad", "Dialpad"), + ("Discord", "Discord"), + ("Discourse", "Discourse"), + ("Donorbox", "Donorbox"), + ("Doorloop", "Doorloop"), + ("Dovetail", "Dovetail"), + ("Drchrono", "Drchrono"), + ("Dynamics365BusinessCentral", "Dynamics365BusinessCentral"), + ("EcbDataPortal", "EcbDataPortal"), + ("Emarsys", "Emarsys"), + ("Embrace", "Embrace"), + ("Entsoe", "Entsoe"), + ("Eppo", "Eppo"), + ("Etsy", "Etsy"), + ("Eurostat", "Eurostat"), + ("Faire", "Faire"), + ("FarosAi", "FarosAi"), + ("Fieldpulse", "Fieldpulse"), + ("Fieldwire", "Fieldwire"), + ("Filevine", "Filevine"), + ("Finout", "Finout"), + ("Five9", "Five9"), + ("FlexeraCloudCost", "FlexeraCloudCost"), + ("Flutterwave", "Flutterwave"), + ("Fortnox", "Fortnox"), + ("Fourthwall", "Fourthwall"), + ("Fred", "Fred"), + ("Frontegg", "Frontegg"), + ("FusionAuth", "FusionAuth"), + ("G2", "G2"), + ("Gcore", "Gcore"), + ("GcpApigee", "GcpApigee"), + ("GcpArtifactRegistry", "GcpArtifactRegistry"), + ("GcpBigtable", "GcpBigtable"), + ("GcpChronicle", "GcpChronicle"), + ("GcpCloudAssetInventory", "GcpCloudAssetInventory"), + ("GcpCloudBilling", "GcpCloudBilling"), + ("GcpCloudBuild", "GcpCloudBuild"), + ("GcpCloudDeploy", "GcpCloudDeploy"), + ("GcpCloudDns", "GcpCloudDns"), + ("GcpCloudFunctions", "GcpCloudFunctions"), + ("GcpCloudLogging", "GcpCloudLogging"), + ("GcpCloudMonitoring", "GcpCloudMonitoring"), + ("GcpCloudRun", "GcpCloudRun"), + ("GcpCloudSpanner", "GcpCloudSpanner"), + ("GcpCloudSql", "GcpCloudSql"), + ("GcpCloudTrace", "GcpCloudTrace"), + ("GcpCloudWorkflows", "GcpCloudWorkflows"), + ("GcpComputeEngine", "GcpComputeEngine"), + ("GcpContainerAnalysis", "GcpContainerAnalysis"), + ("GcpDataflow", "GcpDataflow"), + ("GcpDataplex", "GcpDataplex"), + ("GcpDataproc", "GcpDataproc"), + ("GcpErrorReporting", "GcpErrorReporting"), + ("GcpGke", "GcpGke"), + ("GcpPubsub", "GcpPubsub"), + ("GcpRecaptchaEnterprise", "GcpRecaptchaEnterprise"), + ("GcpRecommender", "GcpRecommender"), + ("GcpSecurityCommandCenter", "GcpSecurityCommandCenter"), + ("Gdelt", "Gdelt"), + ("GenesysCloud", "GenesysCloud"), + ("Getdx", "Getdx"), + ("Ghost", "Ghost"), + ("Givebutter", "Givebutter"), + ("Gleif", "Gleif"), + ("GooglePlayConsole", "GooglePlayConsole"), + ("Guesty", "Guesty"), + ("Gumroad", "Gumroad"), + ("HarnessCcm", "HarnessCcm"), + ("HarnessSei", "HarnessSei"), + ("Harvest", "Harvest"), + ("Healthie", "Healthie"), + ("Hitpay", "Hitpay"), + ("Hivebrite", "Hivebrite"), + ("Holded", "Holded"), + ("Hostaway", "Hostaway"), + ("HousecallPro", "HousecallPro"), + ("Humanitec", "Humanitec"), + ("ImfData", "ImfData"), + ("Imperva", "Imperva"), + ("InfluxdbCloud", "InfluxdbCloud"), + ("Iyzico", "Iyzico"), + ("Jobtread", "Jobtread"), + ("Kameleoon", "Kameleoon"), + ("KauflandMarketplace", "KauflandMarketplace"), + ("Kestra", "Kestra"), + ("Kick", "Kick"), + ("Kinde", "Kinde"), + ("Kion", "Kion"), + ("Knowbe4", "Knowbe4"), + ("Komodor", "Komodor"), + ("Labelbox", "Labelbox"), + ("Lawmatics", "Lawmatics"), + ("Learnworlds", "Learnworlds"), + ("LexwareOffice", "LexwareOffice"), + ("Lightdash", "Lightdash"), + ("Lodgify", "Lodgify"), + ("Logicmonitor", "Logicmonitor"), + ("Logrocket", "Logrocket"), + ("LoopReturns", "LoopReturns"), + ("Mastodon", "Mastodon"), + ("Meetup", "Meetup"), + ("Memberful", "Memberful"), + ("MercadoPago", "MercadoPago"), + ("Meteostat", "Meteostat"), + ("Mews", "Mews"), + ("Mezmo", "Mezmo"), + ("Microsoft365UsageReports", "Microsoft365UsageReports"), + ("MicrosoftAdvertising", "MicrosoftAdvertising"), + ("MicrosoftClarity", "MicrosoftClarity"), + ("MicrosoftDefenderCloudApps", "MicrosoftDefenderCloudApps"), + ("MicrosoftDefenderEndpoint", "MicrosoftDefenderEndpoint"), + ("MicrosoftDefenderForCloud", "MicrosoftDefenderForCloud"), + ("MicrosoftIntune", "MicrosoftIntune"), + ("MicrosoftPurview", "MicrosoftPurview"), + ("MicrosoftPurviewAudit", "MicrosoftPurviewAudit"), + ("MicrosoftSentinel", "MicrosoftSentinel"), + ("MicrosoftTeamsCallRecords", "MicrosoftTeamsCallRecords"), + ("Midtrans", "Midtrans"), + ("MightyNetworks", "MightyNetworks"), + ("Mindbody", "Mindbody"), + ("Mirakl", "Mirakl"), + ("Moesif", "Moesif"), + ("Moneybird", "Moneybird"), + ("Moodle", "Moodle"), + ("Motherduck", "Motherduck"), + ("Mycase", "Mycase"), + ("NagerDate", "NagerDate"), + ("NeonCrm", "NeonCrm"), + ("Nexhealth", "Nexhealth"), + ("NoaaCdo", "NoaaCdo"), + ("Nobl9", "Nobl9"), + ("Nolt", "Nolt"), + ("Nops", "Nops"), + ("NpmRegistry", "NpmRegistry"), + ("Oecd", "Oecd"), + ("Okendo", "Okendo"), + ("Omni", "Omni"), + ("Onelogin", "Onelogin"), + ("OpenDental", "OpenDental"), + ("OpenMeteo", "OpenMeteo"), + ("Openalex", "Openalex"), + ("Opencorporates", "Opencorporates"), + ("Openfec", "Openfec"), + ("OpnPayments", "OpnPayments"), + ("Opslevel", "Opslevel"), + ("OttoMarket", "OttoMarket"), + ("Ownerrez", "Ownerrez"), + ("Pagbank", "Pagbank"), + ("Patreon", "Patreon"), + ("Pax8", "Pax8"), + ("Paychex", "Paychex"), + ("Paymob", "Paymob"), + ("Paymongo", "Paymongo"), + ("Phonepe", "Phonepe"), + ("Pike13", "Pike13"), + ("Pingone", "Pingone"), + ("PinterestOrganic", "PinterestOrganic"), + ("PlanningCenter", "PlanningCenter"), + ("PluralsightFlow", "PluralsightFlow"), + ("Podbean", "Podbean"), + ("Postscript", "Postscript"), + ("PowerBiAdmin", "PowerBiAdmin"), + ("Practicepanther", "Practicepanther"), + ("Preset", "Preset"), + ("Procore", "Procore"), + ("Productiv", "Productiv"), + ("ProofpointTap", "ProofpointTap"), + ("Propertyware", "Propertyware"), + ("Pubnub", "Pubnub"), + ("Quay", "Quay"), + ("Raken", "Raken"), + ("RedpandaCloud", "RedpandaCloud"), + ("RentManager", "RentManager"), + ("Reverb", "Reverb"), + ("RocketMatter", "RocketMatter"), + ("Rubygems", "Rubygems"), + ("Scalr", "Scalr"), + ("SecEdgar", "SecEdgar"), + ("SelectStar", "SelectStar"), + ("SemanticScholar", "SemanticScholar"), + ("Semrush", "Semrush"), + ("ServiceFusion", "ServiceFusion"), + ("Servicem8", "Servicem8"), + ("Servicetitan", "Servicetitan"), + ("Servicetrade", "Servicetrade"), + ("Sevdesk", "Sevdesk"), + ("Similarweb", "Similarweb"), + ("Simpro", "Simpro"), + ("Sinch", "Sinch"), + ("Singlestore", "Singlestore"), + ("Site24x7", "Site24x7"), + ("Sleuth", "Sleuth"), + ("Smartlook", "Smartlook"), + ("Smartrecruiters", "Smartrecruiters"), + ("Smokeball", "Smokeball"), + ("SodaCloud", "SodaCloud"), + ("Speedcurve", "Speedcurve"), + ("SpotIo", "SpotIo"), + ("Sprig", "Sprig"), + ("Sprinklr", "Sprinklr"), + ("SproutSocial", "SproutSocial"), + ("StackOverflowForTeams", "StackOverflowForTeams"), + ("Stockx", "Stockx"), + ("TackleIo", "TackleIo"), + ("Talkdesk", "Talkdesk"), + ("TeamupFitness", "TeamupFitness"), + ("Tebra", "Tebra"), + ("Telnyx", "Telnyx"), + ("Ternary", "Ternary"), + ("Thoughtspot", "Thoughtspot"), + ("Thousandeyes", "Thousandeyes"), + ("Threads", "Threads"), + ("TiktokShop", "TiktokShop"), + ("TinyErp", "TinyErp"), + ("Tinybird", "Tinybird"), + ("Tipalti", "Tipalti"), + ("Toast", "Toast"), + ("Torii", "Torii"), + ("Transistor", "Transistor"), + ("TrunkIo", "TrunkIo"), + ("Trustradius", "Trustradius"), + ("Twitch", "Twitch"), + ("TwoC2p", "TwoC2p"), + ("UkCompaniesHouse", "UkCompaniesHouse"), + ("UkOns", "UkOns"), + ("UnComtrade", "UnComtrade"), + ("UsBea", "UsBea"), + ("UsBls", "UsBls"), + ("UsEia", "UsEia"), + ("UsTreasuryFiscalData", "UsTreasuryFiscalData"), + ("Vanta", "Vanta"), + ("Vendr", "Vendr"), + ("Virtuous", "Virtuous"), + ("Vonage", "Vonage"), + ("WalmartMarketplace", "WalmartMarketplace"), + ("Waydev", "Waydev"), + ("Wayfair", "Wayfair"), + ("WhatsappBusinessManagement", "WhatsappBusinessManagement"), + ("WhoGho", "WhoGho"), + ("Whop", "Whop"), + ("Wiz", "Wiz"), + ("Wompi", "Wompi"), + ("Workiz", "Workiz"), + ("WorldBank", "WorldBank"), + ("Xendit", "Xendit"), + ("Yoco", "Yoco"), + ("ZalandoZdirect", "ZalandoZdirect"), + ("Zluri", "Zluri"), + ("Zylo", "Zylo"), + ("Tally", "Tally"), + ("Nuntly", "Nuntly"), + ("Vturb", "Vturb"), + ("Meltwater", "Meltwater"), + ("UserCom", "UserCom"), + ("Latitude", "Latitude"), + ("Workato", "Workato"), + ("SideShift", "SideShift"), + ("DuckLake", "DuckLake"), + ("Starburst", "Starburst"), + ("Easybill", "Easybill"), + ("Bexio", "Bexio"), + ("Umami", "Umami"), + ("Manychat", "Manychat"), + ("Kickstarter", "Kickstarter"), + ("Typesense", "Typesense"), + ("FirstPromoter", "FirstPromoter"), + ("Zero", "Zero"), + ("Inth", "Inth"), + ("BCMS", "BCMS"), + ("Convonite", "Convonite"), + ("Hookdeck", "Hookdeck"), + ("Billit", "Billit"), + ("Moxie", "Moxie"), + ("TripleWhale", "TripleWhale"), + ("Directus", "Directus"), + ("Clay", "Clay"), + ("TradableBits", "TradableBits"), + ("Swan", "Swan"), + ("Hyros", "Hyros"), + ("Odoo", "Odoo"), + ("Airbridge", "Airbridge"), + ("Snovio", "Snovio"), + ], + max_length=128, + ), + ), + ] diff --git a/products/warehouse_sources/backend/migrations/max_migration.txt b/products/warehouse_sources/backend/migrations/max_migration.txt index 67632785cded..0fb50434b738 100644 --- a/products/warehouse_sources/backend/migrations/max_migration.txt +++ b/products/warehouse_sources/backend/migrations/max_migration.txt @@ -1 +1 @@ -0115_scaffold_four_requested_sources +0116_shipmail_source diff --git a/products/warehouse_sources/backend/temporal/data_imports/sources/SOURCES.md b/products/warehouse_sources/backend/temporal/data_imports/sources/SOURCES.md index 15887e4cde62..6069e7f5cd8b 100644 --- a/products/warehouse_sources/backend/temporal/data_imports/sources/SOURCES.md +++ b/products/warehouse_sources/backend/temporal/data_imports/sources/SOURCES.md @@ -536,6 +536,7 @@ the row lists both. | sentinelone | HTTP | requests | ✅ | | sentry | HTTP | requests + `rest_source.RESTClient` | ✅ | | servicenow | HTTP | requests | ✅ | +| shipmail | HTTP | requests + `rest_source.RESTClient` | ✅ | | shippo | HTTP | requests | ✅ | | shipstation | HTTP | requests | ✅ | | shopify | HTTP | requests | ✅ | diff --git a/products/warehouse_sources/backend/temporal/data_imports/sources/_load_all.py b/products/warehouse_sources/backend/temporal/data_imports/sources/_load_all.py index 6b310668384c..473f587b34f3 100644 --- a/products/warehouse_sources/backend/temporal/data_imports/sources/_load_all.py +++ b/products/warehouse_sources/backend/temporal/data_imports/sources/_load_all.py @@ -1022,6 +1022,7 @@ from .sftp.source import SFTPSource from .sharepoint.source import SharePointSource from .sharetribe.source import SharetribeSource +from .shipmail.source import ShipmailSource from .shippo.source import ShippoSource from .shipstation.source import ShipStationSource from .shopify.source import ShopifySource diff --git a/products/warehouse_sources/backend/temporal/data_imports/sources/generated_configs/shipmail.py b/products/warehouse_sources/backend/temporal/data_imports/sources/generated_configs/shipmail.py new file mode 100644 index 000000000000..b0379a236fee --- /dev/null +++ b/products/warehouse_sources/backend/temporal/data_imports/sources/generated_configs/shipmail.py @@ -0,0 +1,9 @@ +# This file is automatically generated from `SourceRegistry.get_all_sources()` +# Do not edit manually - run `pnpm generate:source-configs` to regenerate. + +from products.warehouse_sources.backend.temporal.data_imports.sources.common import config + + +@config.config +class ShipmailSourceConfig(config.Config): + api_key: str diff --git a/products/warehouse_sources/backend/temporal/data_imports/sources/shipmail/canonical_descriptions.py b/products/warehouse_sources/backend/temporal/data_imports/sources/shipmail/canonical_descriptions.py new file mode 100644 index 000000000000..ebf6b3543d78 --- /dev/null +++ b/products/warehouse_sources/backend/temporal/data_imports/sources/shipmail/canonical_descriptions.py @@ -0,0 +1,79 @@ +"""Canonical descriptions sourced from the Shipmail API documentation.""" + +from products.warehouse_sources.backend.temporal.data_imports.sources.common.canonical_descriptions import ( + CanonicalDescriptions, +) + +CANONICAL_DESCRIPTIONS: CanonicalDescriptions = { + "messages": { + "description": "Analytics-safe message records in stable update order, without message content or sensitive headers.", + "docs_url": "https://shipmail.to/docs/api/messages", + "columns": { + "object": "The API object type. Always `message_analytics`.", + "id": "Unique identifier for the message.", + "mailbox_id": "Identifier of the mailbox associated with the message.", + "thread_id": "Identifier of the conversation thread, when available.", + "client_reference": "Caller-provided reference used to associate the message with an external record.", + "direction": "Whether the message was inbound or outbound.", + "contact_addresses": "Email addresses of contacts involved in the message.", + "recipient_count": "Number of recipients on the message.", + "attachment_count": "Number of attachments on the message.", + "source": "System or integration that created the message.", + "mode": "Whether the message belongs to live or sandbox data.", + "status": "Current message status.", + "scheduled_at": "Time at which the message was scheduled to be sent, when applicable.", + "created_at": "Time at which the message was created.", + "updated_at": "Time at which the message was last updated.", + }, + }, + "mailboxes": { + "description": "Mailboxes belonging to the authenticated Shipmail organization.", + "docs_url": "https://shipmail.to/docs/api/mailboxes", + "columns": { + "object": "The API object type. Always `mailbox`.", + "id": "Unique identifier for the mailbox.", + "domain_id": "Identifier of the domain that hosts the mailbox.", + "address": "Email address of the mailbox.", + "display_name": "Display name used for the mailbox.", + "suspended_at": "Time at which the mailbox was suspended, when applicable.", + "suspension_reasons": "Reasons the mailbox is suspended.", + "spam_filter_threshold": "Spam score threshold applied to inbound messages.", + "auto_reply": "Automatic reply configuration for the mailbox.", + "created_at": "Time at which the mailbox was created.", + "updated_at": "Time at which the mailbox was last updated.", + }, + }, + "domains": { + "description": "Sending and receiving domains configured in the authenticated Shipmail organization.", + "docs_url": "https://shipmail.to/docs/api/domains", + "columns": { + "object": "The API object type. Always `domain`.", + "id": "Unique identifier for the domain.", + "name": "Domain name.", + "status": "Current domain status.", + "managed_by": "Whether DNS is managed externally or by Shipmail.", + "dns_provider": "Detected DNS provider, when available.", + "mx_verified": "Whether the MX record is verified.", + "spf_verified": "Whether the SPF record is verified.", + "dkim_verified": "Whether the DKIM record is verified.", + "dmarc_verified": "Whether the DMARC record is verified.", + "dmarc_managed_externally": "Whether DMARC is managed outside Shipmail.", + "outbound_verified": "Whether outbound sending is verified.", + "catch_all_mailbox_id": "Identifier of the catch-all mailbox, when configured.", + "verified_at": "Time at which the domain completed verification.", + "created_at": "Time at which the domain was created.", + "updated_at": "Time at which the domain was last updated.", + "registration": "Registration details for domains managed by Shipmail, when available.", + }, + }, + "suppressions": { + "description": "Email addresses suppressed from outbound delivery.", + "docs_url": "https://shipmail.to/docs/api/suppressions", + "columns": { + "object": "The API object type. Always `suppression`.", + "email_address": "Suppressed email address.", + "reason": "Reason the address was suppressed.", + "created_at": "Time at which the suppression was created.", + }, + }, +} diff --git a/products/warehouse_sources/backend/temporal/data_imports/sources/shipmail/settings.py b/products/warehouse_sources/backend/temporal/data_imports/sources/shipmail/settings.py new file mode 100644 index 000000000000..4e031115c901 --- /dev/null +++ b/products/warehouse_sources/backend/temporal/data_imports/sources/shipmail/settings.py @@ -0,0 +1,53 @@ +from dataclasses import dataclass, field + +from products.warehouse_sources.backend.temporal.data_imports.sources.common.schema import incremental_field +from products.warehouse_sources.backend.types import IncrementalField + + +@dataclass(frozen=True) +class ShipmailEndpointConfig: + name: str + path: str + primary_keys: list[str] + required_scope: str + partition_key: str + incremental_fields: list[IncrementalField] = field(default_factory=list) + + +SHIPMAIL_ENDPOINTS: dict[str, ShipmailEndpointConfig] = { + "messages": ShipmailEndpointConfig( + name="messages", + path="/messages/analytics", + primary_keys=["id"], + required_scope="messages:read", + partition_key="created_at", + incremental_fields=[incremental_field("updated_at")], + ), + "mailboxes": ShipmailEndpointConfig( + name="mailboxes", + path="/mailboxes", + primary_keys=["id"], + required_scope="mailboxes:read", + partition_key="created_at", + ), + "domains": ShipmailEndpointConfig( + name="domains", + path="/domains", + primary_keys=["id"], + required_scope="domains:read", + partition_key="created_at", + ), + "suppressions": ShipmailEndpointConfig( + name="suppressions", + path="/suppressions", + primary_keys=["email_address"], + required_scope="suppressions:read", + partition_key="created_at", + ), +} + +ENDPOINTS = tuple(SHIPMAIL_ENDPOINTS.keys()) + +INCREMENTAL_FIELDS: dict[str, list[IncrementalField]] = { + name: config.incremental_fields for name, config in SHIPMAIL_ENDPOINTS.items() if config.incremental_fields +} diff --git a/products/warehouse_sources/backend/temporal/data_imports/sources/shipmail/shipmail.py b/products/warehouse_sources/backend/temporal/data_imports/sources/shipmail/shipmail.py new file mode 100644 index 000000000000..23613531520d --- /dev/null +++ b/products/warehouse_sources/backend/temporal/data_imports/sources/shipmail/shipmail.py @@ -0,0 +1,130 @@ +import dataclasses +from datetime import datetime +from typing import Any, Optional + +from products.warehouse_sources.backend.temporal.data_imports.sources.common.http import make_tracked_session +from products.warehouse_sources.backend.temporal.data_imports.sources.common.rest_source import ( + RESTAPIConfig, + rest_api_resource, +) +from products.warehouse_sources.backend.temporal.data_imports.sources.common.rest_source.paginators import ( + JSONResponseCursorPaginator, +) +from products.warehouse_sources.backend.temporal.data_imports.sources.common.resumable import ResumableSourceManager +from products.warehouse_sources.backend.temporal.data_imports.sources.common.typings import SourceResponse +from products.warehouse_sources.backend.temporal.data_imports.sources.shipmail.settings import SHIPMAIL_ENDPOINTS + +SHIPMAIL_BASE_URL = "https://shipmail.to/api/v1" + + +@dataclasses.dataclass +class ShipmailResumeConfig: + cursor: str | None = None + + +def _incremental_value(value: Any) -> str: + if isinstance(value, datetime): + return value.isoformat() + return str(value) + + +def _initial_paginator_state( + resumable_source_manager: ResumableSourceManager[ShipmailResumeConfig], +) -> dict[str, str] | None: + if not resumable_source_manager.can_resume(): + return None + resume = resumable_source_manager.load_state() + if resume is None or resume.cursor is None: + return None + return {"cursor": resume.cursor} + + +def shipmail_source( + api_key: str, + endpoint: str, + team_id: int, + job_id: str, + resumable_source_manager: ResumableSourceManager[ShipmailResumeConfig], + should_use_incremental_field: bool = False, + db_incremental_field_last_value: Optional[Any] = None, + incremental_field: Optional[str] = None, +) -> SourceResponse: + endpoint_config = SHIPMAIL_ENDPOINTS[endpoint] + params: dict[str, Any] = {"limit": 100} + + if ( + endpoint == "messages" + and should_use_incremental_field + and incremental_field == "updated_at" + and db_incremental_field_last_value is not None + ): + params["updated_after"] = _incremental_value(db_incremental_field_last_value) + + rest_config: RESTAPIConfig = { + "client": { + "base_url": SHIPMAIL_BASE_URL, + "headers": {"Accept": "application/json"}, + "auth": {"type": "bearer", "token": api_key}, + "paginator": JSONResponseCursorPaginator( + cursor_path="pagination.next_cursor", + cursor_param="cursor", + ), + "session": make_tracked_session(redact_values=(api_key,), capture=False), + }, + "resource_defaults": {}, + "resources": [ + { + "name": endpoint, + "endpoint": { + "path": endpoint_config.path, + "params": params, + "data_selector": "data", + "data_selector_required": True, + }, + } + ], + } + + def save_checkpoint(state: dict[str, Any] | None) -> None: + if state and state.get("cursor"): + resumable_source_manager.save_state(ShipmailResumeConfig(cursor=str(state["cursor"]))) + + resource = rest_api_resource( + rest_config, + team_id, + job_id, + db_incremental_field_last_value, + resume_hook=save_checkpoint, + initial_paginator_state=_initial_paginator_state(resumable_source_manager), + ) + + return SourceResponse( + name=endpoint, + items=lambda: resource, + primary_keys=endpoint_config.primary_keys, + partition_count=1, + partition_size=1, + partition_mode="datetime", + partition_format="month", + partition_keys=[endpoint_config.partition_key], + sort_mode="asc" if endpoint == "messages" else "desc", + ) + + +def get_capabilities(api_key: str) -> tuple[int | None, set[str]]: + try: + session = make_tracked_session(redact_values=(api_key,), capture=False) + response = session.get( + f"{SHIPMAIL_BASE_URL}/capabilities", + headers={"Authorization": f"Bearer {api_key}", "Accept": "application/json"}, + timeout=10, + ) + if response.status_code != 200: + return response.status_code, set() + body = response.json() + scopes = body.get("scopes") + if not isinstance(scopes, list) or not all(isinstance(scope, str) for scope in scopes): + return response.status_code, set() + return response.status_code, {scope for scope in scopes if isinstance(scope, str)} + except Exception: # noqa: BLE001 - credential probes must return a validation result, never raise + return None, set() diff --git a/products/warehouse_sources/backend/temporal/data_imports/sources/shipmail/source.py b/products/warehouse_sources/backend/temporal/data_imports/sources/shipmail/source.py new file mode 100644 index 000000000000..b595281cfb4c --- /dev/null +++ b/products/warehouse_sources/backend/temporal/data_imports/sources/shipmail/source.py @@ -0,0 +1,168 @@ +from typing import Optional, cast + +from posthog.schema import ( + DataWarehouseSourceCategory, + ExternalDataSourceType as SchemaExternalDataSourceType, + ReleaseStatus, + SourceConfig, + SourceFieldInputConfig, + SourceFieldInputConfigType, +) + +from products.warehouse_sources.backend.temporal.data_imports.sources.common.base import FieldType, ResumableSource +from products.warehouse_sources.backend.temporal.data_imports.sources.common.canonical_descriptions import ( + CanonicalDescriptions, +) +from products.warehouse_sources.backend.temporal.data_imports.sources.common.registry import SourceRegistry +from products.warehouse_sources.backend.temporal.data_imports.sources.common.resumable import ResumableSourceManager +from products.warehouse_sources.backend.temporal.data_imports.sources.common.schema import SourceSchema +from products.warehouse_sources.backend.temporal.data_imports.sources.common.typings import SourceInputs, SourceResponse +from products.warehouse_sources.backend.temporal.data_imports.sources.generated_configs.shipmail import ( + ShipmailSourceConfig, +) +from products.warehouse_sources.backend.temporal.data_imports.sources.shipmail.settings import SHIPMAIL_ENDPOINTS +from products.warehouse_sources.backend.temporal.data_imports.sources.shipmail.shipmail import ( + ShipmailResumeConfig, + get_capabilities, + shipmail_source, +) +from products.warehouse_sources.backend.types import ExternalDataSourceType + + +@SourceRegistry.register +class ShipmailSource(ResumableSource[ShipmailSourceConfig, ShipmailResumeConfig]): + lists_tables_without_credentials = True + api_docs_url = "https://shipmail.to/docs/api" + + @property + def source_type(self) -> ExternalDataSourceType: + return ExternalDataSourceType.SHIPMAIL + + @property + def get_source_config(self) -> SourceConfig: + return SourceConfig( + name=SchemaExternalDataSourceType.SHIPMAIL, + category=DataWarehouseSourceCategory.MARKETING___EMAIL, + label="Shipmail", + releaseStatus=ReleaseStatus.ALPHA, + caption="""Enter your Shipmail API key to sync message analytics, mailboxes, domains, and suppressions into the PostHog Data warehouse. + +Grant the key the read scopes for the tables you want to sync: `messages:read`, `mailboxes:read`, `domains:read`, and `suppressions:read`.""", + iconPath="/static/services/shipmail.png", + docsUrl="https://posthog.com/docs/cdp/sources/shipmail", + fields=cast( + list[FieldType], + [ + SourceFieldInputConfig( + name="api_key", + label="API key", + type=SourceFieldInputConfigType.PASSWORD, + required=True, + placeholder="Shipmail API key", + caption="Create a key in your [Shipmail API settings](https://shipmail.to/settings/api-keys).", + secret=True, + ), + ], + ), + ) + + def get_canonical_descriptions(self) -> CanonicalDescriptions: + from products.warehouse_sources.backend.temporal.data_imports.sources.shipmail.canonical_descriptions import ( + CANONICAL_DESCRIPTIONS, + ) + + return CANONICAL_DESCRIPTIONS + + def get_non_retryable_errors(self) -> dict[str, str | None]: + return { + "401 Client Error: Unauthorized for url: https://shipmail.to": "Your Shipmail API key is invalid or has been revoked. Create a new key and reconnect.", + "403 Client Error: Forbidden for url: https://shipmail.to": "Your Shipmail API key is missing the read scope required for this table.", + } + + def get_schemas( + self, + config: ShipmailSourceConfig, + team_id: int, + with_counts: bool = False, + names: list[str] | None = None, + force_refresh: bool = False, + api_version: str | None = None, + ) -> list[SourceSchema]: + schemas = [ + SourceSchema( + name=name, + supports_incremental=bool(endpoint.incremental_fields), + supports_append=bool(endpoint.incremental_fields), + incremental_fields=endpoint.incremental_fields, + detected_primary_keys=endpoint.primary_keys, + ) + for name, endpoint in SHIPMAIL_ENDPOINTS.items() + ] + if names is not None: + names_set = set(names) + schemas = [schema for schema in schemas if schema.name in names_set] + return schemas + + def validate_credentials( + self, + config: ShipmailSourceConfig, + team_id: int, + schema_name: Optional[str] = None, + api_version: str | None = None, + ) -> tuple[bool, str | None]: + status, scopes = get_capabilities(config.api_key) + if status == 200: + if schema_name in SHIPMAIL_ENDPOINTS: + required_scope = SHIPMAIL_ENDPOINTS[schema_name].required_scope + if "*" not in scopes and required_scope not in scopes: + return False, f"Your Shipmail API key is missing the `{required_scope}` scope" + return True, None + if status == 401: + return False, "Invalid Shipmail API key" + if status == 403: + return False, "Your Shipmail API key cannot access the capabilities endpoint" + return False, "Could not validate Shipmail API key" + + def get_endpoint_permissions( + self, + config: ShipmailSourceConfig, + team_id: int, + endpoints: list[str], + api_version: str | None = None, + ) -> dict[str, str | None]: + status, scopes = get_capabilities(config.api_key) + if status == 401: + return dict.fromkeys(endpoints, "API key is invalid") + if status != 200: + return dict.fromkeys(endpoints) + + permissions: dict[str, str | None] = {} + for endpoint in endpoints: + endpoint_config = SHIPMAIL_ENDPOINTS.get(endpoint) + if endpoint_config is None or "*" in scopes or endpoint_config.required_scope in scopes: + permissions[endpoint] = None + else: + permissions[endpoint] = f"API key is missing the `{endpoint_config.required_scope}` scope" + return permissions + + def get_resumable_source_manager(self, inputs: SourceInputs) -> ResumableSourceManager[ShipmailResumeConfig]: + return ResumableSourceManager[ShipmailResumeConfig](inputs, ShipmailResumeConfig) + + def source_for_pipeline( + self, + config: ShipmailSourceConfig, + resumable_source_manager: ResumableSourceManager[ShipmailResumeConfig], + inputs: SourceInputs, + ) -> SourceResponse: + return shipmail_source( + api_key=config.api_key, + endpoint=inputs.schema_name, + team_id=inputs.team_id, + job_id=inputs.job_id, + resumable_source_manager=resumable_source_manager, + should_use_incremental_field=inputs.should_use_incremental_field, + db_incremental_field_last_value=inputs.db_incremental_field_last_value + if inputs.should_use_incremental_field + else None, + incremental_field=inputs.incremental_field, + ) diff --git a/products/warehouse_sources/backend/temporal/data_imports/sources/shipmail/tests/test_shipmail.py b/products/warehouse_sources/backend/temporal/data_imports/sources/shipmail/tests/test_shipmail.py new file mode 100644 index 000000000000..88a74782c433 --- /dev/null +++ b/products/warehouse_sources/backend/temporal/data_imports/sources/shipmail/tests/test_shipmail.py @@ -0,0 +1,206 @@ +import json +from datetime import UTC, datetime +from typing import Any + +import pytest +from unittest import mock + +from requests import Response + +from products.warehouse_sources.backend.temporal.data_imports.sources.shipmail.shipmail import ( + SHIPMAIL_BASE_URL, + ShipmailResumeConfig, + _incremental_value, + get_capabilities, + shipmail_source, +) + +TRACKED_SESSION_PATCH = ( + "products.warehouse_sources.backend.temporal.data_imports.sources.shipmail.shipmail.make_tracked_session" +) + + +def _response(body: Any, status_code: int = 200) -> Response: + response = Response() + response.status_code = status_code + response._content = json.dumps(body).encode() + return response + + +def _manager(resume_state: ShipmailResumeConfig | None = None) -> mock.MagicMock: + manager = mock.MagicMock() + manager.can_resume.return_value = resume_state is not None + manager.load_state.return_value = resume_state + return manager + + +def _wire(session: mock.MagicMock, responses: list[Response]) -> list[dict[str, Any]]: + session.headers = {} + params: list[dict[str, Any]] = [] + + def prepare(request: Any) -> mock.MagicMock: + params.append(dict(request.params or {})) + return mock.MagicMock() + + session.prepare_request.side_effect = prepare + session.send.side_effect = responses + return params + + +def _source(endpoint: str, manager: mock.MagicMock, **overrides: Any): + return shipmail_source( + "test-key", + endpoint, + team_id=1, + job_id="job", + resumable_source_manager=manager, + **overrides, + ) + + +def _rows(source_response) -> list[dict[str, Any]]: + return [row for page in source_response.items() for row in page] + + +def test_incremental_value_preserves_iso_timestamp() -> None: + value = datetime(2026, 7, 29, 12, 30, tzinfo=UTC) + assert _incremental_value(value) == "2026-07-29T12:30:00+00:00" + assert _incremental_value("2026-07-29T12:30:00Z") == "2026-07-29T12:30:00Z" + + +@mock.patch(TRACKED_SESSION_PATCH) +def test_messages_paginates_checkpoints_and_sends_incremental_watermark(make_session: mock.MagicMock) -> None: + session = make_session.return_value + params = _wire( + session, + [ + _response( + { + "data": [{"id": "msg_1"}], + "pagination": {"next_cursor": "cursor_2", "has_more": True, "limit": 100}, + } + ), + _response( + { + "data": [{"id": "msg_2"}], + "pagination": {"next_cursor": None, "has_more": False, "limit": 100}, + } + ), + ], + ) + manager = _manager() + + rows = _rows( + _source( + "messages", + manager, + should_use_incremental_field=True, + db_incremental_field_last_value="2026-07-01T00:00:00Z", + incremental_field="updated_at", + ) + ) + + assert rows == [{"id": "msg_1"}, {"id": "msg_2"}] + assert params[0] == {"limit": 100, "updated_after": "2026-07-01T00:00:00Z"} + assert params[1] == { + "limit": 100, + "updated_after": "2026-07-01T00:00:00Z", + "cursor": "cursor_2", + } + manager.save_state.assert_called_once_with(ShipmailResumeConfig(cursor="cursor_2")) + make_session.assert_called_once_with(redact_values=("test-key",), capture=False) + + +@mock.patch(TRACKED_SESSION_PATCH) +def test_resumes_from_saved_cursor(make_session: mock.MagicMock) -> None: + session = make_session.return_value + params = _wire( + session, + [ + _response( + { + "data": [{"id": "mbx_2"}], + "pagination": {"next_cursor": None, "has_more": False, "limit": 100}, + } + ) + ], + ) + + rows = _rows(_source("mailboxes", _manager(ShipmailResumeConfig(cursor="cursor_2")))) + + assert rows == [{"id": "mbx_2"}] + assert params[0] == {"limit": 100, "cursor": "cursor_2"} + + +@mock.patch(TRACKED_SESSION_PATCH) +def test_full_refresh_endpoint_does_not_send_incremental_watermark(make_session: mock.MagicMock) -> None: + session = make_session.return_value + params = _wire( + session, + [ + _response( + { + "data": [{"id": "domain_1"}], + "pagination": {"next_cursor": None, "has_more": False, "limit": 100}, + } + ) + ], + ) + + _rows( + _source( + "domains", + _manager(), + should_use_incremental_field=True, + db_incremental_field_last_value="2026-07-01T00:00:00Z", + incremental_field="updated_at", + ) + ) + + assert params[0] == {"limit": 100} + + +@mock.patch(TRACKED_SESSION_PATCH) +def test_missing_data_key_raises(make_session: mock.MagicMock) -> None: + session = make_session.return_value + _wire(session, [_response({"pagination": {"next_cursor": None}})]) + + with pytest.raises(ValueError, match="matched nothing"): + _rows(_source("messages", _manager())) + + +@pytest.mark.parametrize( + ("endpoint", "primary_keys", "sort_mode"), + [ + ("messages", ["id"], "asc"), + ("mailboxes", ["id"], "desc"), + ("domains", ["id"], "desc"), + ("suppressions", ["email_address"], "desc"), + ], +) +def test_source_response_metadata(endpoint: str, primary_keys: list[str], sort_mode: str) -> None: + response = _source(endpoint, _manager()) + assert response.primary_keys == primary_keys + assert response.partition_keys == ["created_at"] + assert response.partition_format == "month" + assert response.sort_mode == sort_mode + + +@mock.patch(TRACKED_SESSION_PATCH) +def test_get_capabilities_returns_status_and_scopes(make_session: mock.MagicMock) -> None: + session = make_session.return_value + session.get.return_value = _response({"scopes": ["messages:read", "domains:read"]}) + + assert get_capabilities("secret-key") == (200, {"messages:read", "domains:read"}) + session.get.assert_called_once_with( + f"{SHIPMAIL_BASE_URL}/capabilities", + headers={"Authorization": "Bearer secret-key", "Accept": "application/json"}, + timeout=10, + ) + make_session.assert_called_once_with(redact_values=("secret-key",), capture=False) + + +@mock.patch(TRACKED_SESSION_PATCH) +def test_get_capabilities_handles_invalid_credentials(make_session: mock.MagicMock) -> None: + make_session.return_value.get.return_value = _response({"error": "unauthorized"}, status_code=401) + assert get_capabilities("bad-key") == (401, set()) diff --git a/products/warehouse_sources/backend/temporal/data_imports/sources/shipmail/tests/test_shipmail_source.py b/products/warehouse_sources/backend/temporal/data_imports/sources/shipmail/tests/test_shipmail_source.py new file mode 100644 index 000000000000..2da1985a4c09 --- /dev/null +++ b/products/warehouse_sources/backend/temporal/data_imports/sources/shipmail/tests/test_shipmail_source.py @@ -0,0 +1,72 @@ +from unittest import mock + +from posthog.schema import ReleaseStatus + +from products.warehouse_sources.backend.temporal.data_imports.sources.generated_configs.shipmail import ( + ShipmailSourceConfig, +) +from products.warehouse_sources.backend.temporal.data_imports.sources.shipmail.source import ShipmailSource +from products.warehouse_sources.backend.types import ExternalDataSourceType + +CAPABILITIES_PATCH = "products.warehouse_sources.backend.temporal.data_imports.sources.shipmail.source.get_capabilities" + + +class TestShipmailSource: + def setup_method(self) -> None: + self.source = ShipmailSource() + self.config = ShipmailSourceConfig(api_key="test-key") + + def test_source_metadata(self) -> None: + assert self.source.source_type == ExternalDataSourceType.SHIPMAIL + assert self.source.lists_tables_without_credentials is True + assert self.source.get_source_config.releaseStatus == ReleaseStatus.ALPHA + + def test_static_schemas_include_keys_and_incremental_support(self) -> None: + schemas = {schema.name: schema for schema in self.source.get_schemas(self.config, team_id=1)} + + assert set(schemas) == {"messages", "mailboxes", "domains", "suppressions"} + assert schemas["messages"].supports_incremental is True + assert schemas["messages"].detected_primary_keys == ["id"] + assert schemas["mailboxes"].supports_incremental is False + assert schemas["suppressions"].detected_primary_keys == ["email_address"] + + def test_schema_filter(self) -> None: + schemas = self.source.get_schemas(self.config, team_id=1, names=["domains"]) + assert [schema.name for schema in schemas] == ["domains"] + + def test_documented_tables_are_available_without_credentials(self) -> None: + tables = {table["name"]: table for table in self.source.get_documented_tables()} + + assert set(tables) == {"messages", "mailboxes", "domains", "suppressions"} + assert tables["messages"]["sync_methods"] == ["Incremental", "Full refresh"] + assert tables["messages"]["incremental_fields"] == ["updated_at"] + assert tables["messages"]["primary_keys"] == ["id"] + assert tables["suppressions"]["primary_keys"] == ["email_address"] + + @mock.patch(CAPABILITIES_PATCH, return_value=(200, {"messages:read"})) + def test_validates_token_without_requiring_every_table_scope(self, get_capabilities: mock.MagicMock) -> None: + assert self.source.validate_credentials(self.config, team_id=1) == (True, None) + assert self.source.validate_credentials(self.config, team_id=1, schema_name="messages") == (True, None) + assert self.source.validate_credentials(self.config, team_id=1, schema_name="domains") == ( + False, + "Your Shipmail API key is missing the `domains:read` scope", + ) + + @mock.patch(CAPABILITIES_PATCH, return_value=(200, {"messages:read", "suppressions:read"})) + def test_endpoint_permissions_use_one_capabilities_response(self, get_capabilities: mock.MagicMock) -> None: + permissions = self.source.get_endpoint_permissions( + self.config, + team_id=1, + endpoints=["messages", "mailboxes", "suppressions"], + ) + + assert permissions == { + "messages": None, + "mailboxes": "API key is missing the `mailboxes:read` scope", + "suppressions": None, + } + get_capabilities.assert_called_once_with("test-key") + + @mock.patch(CAPABILITIES_PATCH, return_value=(401, set())) + def test_rejects_invalid_token(self, get_capabilities: mock.MagicMock) -> None: + assert self.source.validate_credentials(self.config, team_id=1) == (False, "Invalid Shipmail API key") diff --git a/products/warehouse_sources/backend/types.py b/products/warehouse_sources/backend/types.py index 3ba62f5a64fd..ac9f06077eeb 100644 --- a/products/warehouse_sources/backend/types.py +++ b/products/warehouse_sources/backend/types.py @@ -217,6 +217,7 @@ class ExternalDataSourceType(models.TextChoices): EBAY = "Ebay", "Ebay" COMMERCETOOLS = "Commercetools", "Commercetools" LIGHTSPEEDRETAIL = "LightspeedRetail", "LightspeedRetail" + SHIPMAIL = "Shipmail", "Shipmail" SHIPSTATION = "ShipStation", "ShipStation" CONSTANTCONTACT = "ConstantContact", "ConstantContact" MAILGUN = "Mailgun", "Mailgun" diff --git a/products/warehouse_sources/frontend/generated/api.schemas.ts b/products/warehouse_sources/frontend/generated/api.schemas.ts index daa487a72ac4..1072d7249db2 100644 --- a/products/warehouse_sources/frontend/generated/api.schemas.ts +++ b/products/warehouse_sources/frontend/generated/api.schemas.ts @@ -605,6 +605,7 @@ export const ExternalDataSourceSerializersCreatedViaEnumApi = { * * `Ebay` - Ebay * * `Commercetools` - Commercetools * * `LightspeedRetail` - LightspeedRetail + * * `Shipmail` - Shipmail * * `ShipStation` - ShipStation * * `ConstantContact` - ConstantContact * * `Mailgun` - Mailgun @@ -1886,6 +1887,7 @@ export const ExternalDataSourceTypeEnumApi = { Ebay: 'Ebay', Commercetools: 'Commercetools', LightspeedRetail: 'LightspeedRetail', + Shipmail: 'Shipmail', ShipStation: 'ShipStation', ConstantContact: 'ConstantContact', Mailgun: 'Mailgun', @@ -3307,6 +3309,7 @@ export interface ExternalDataSourceCreateApi { * * `Ebay` - Ebay * * `Commercetools` - Commercetools * * `LightspeedRetail` - LightspeedRetail + * * `Shipmail` - Shipmail * * `ShipStation` - ShipStation * * `ConstantContact` - ConstantContact * * `Mailgun` - Mailgun @@ -4802,6 +4805,7 @@ export interface ExternalDataSourceConnectionOptionApi { * * `Ebay` - Ebay * * `Commercetools` - Commercetools * * `LightspeedRetail` - LightspeedRetail + * * `Shipmail` - Shipmail * * `ShipStation` - ShipStation * * `ConstantContact` - ConstantContact * * `Mailgun` - Mailgun @@ -6110,6 +6114,7 @@ export interface DatabaseSchemaRequestApi { * * `Ebay` - Ebay * * `Commercetools` - Commercetools * * `LightspeedRetail` - LightspeedRetail + * * `Shipmail` - Shipmail * * `ShipStation` - ShipStation * * `ConstantContact` - ConstantContact * * `Mailgun` - Mailgun @@ -7395,6 +7400,7 @@ export interface DirectConnectionSourceOptionApi { * * `Ebay` - Ebay * * `Commercetools` - Commercetools * * `LightspeedRetail` - LightspeedRetail + * * `Shipmail` - Shipmail * * `ShipStation` - ShipStation * * `ConstantContact` - ConstantContact * * `Mailgun` - Mailgun @@ -8765,6 +8771,7 @@ export interface SourcePreviewRequestApi { * * `Ebay` - Ebay * * `Commercetools` - Commercetools * * `LightspeedRetail` - LightspeedRetail + * * `Shipmail` - Shipmail * * `ShipStation` - ShipStation * * `ConstantContact` - ConstantContact * * `Mailgun` - Mailgun @@ -10085,6 +10092,7 @@ export interface SourceSetupApi { * * `Ebay` - Ebay * * `Commercetools` - Commercetools * * `LightspeedRetail` - LightspeedRetail + * * `Shipmail` - Shipmail * * `ShipStation` - ShipStation * * `ConstantContact` - ConstantContact * * `Mailgun` - Mailgun @@ -11412,6 +11420,7 @@ export interface SourceCredentialCreateApi { * * `Ebay` - Ebay * * `Commercetools` - Commercetools * * `LightspeedRetail` - LightspeedRetail + * * `Shipmail` - Shipmail * * `ShipStation` - ShipStation * * `ConstantContact` - ConstantContact * * `Mailgun` - Mailgun