Add Activepieces integration for workflow automation

- Add Activepieces fork with SmoothSchedule custom piece
- Create integrations app with Activepieces service layer
- Add embed token endpoint for iframe integration
- Create Automations page with embedded workflow builder
- Add sidebar visibility fix for embed mode
- Add list inactive customers endpoint to Public API
- Include SmoothSchedule triggers: event created/updated/cancelled
- Include SmoothSchedule actions: create/update/cancel events, list resources/services/customers

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
poduck
2025-12-18 22:59:37 -05:00
parent 9848268d34
commit 3aa7199503
16292 changed files with 1284892 additions and 4708 deletions

View File

@@ -0,0 +1,33 @@
{
"extends": [
"../../../../.eslintrc.base.json"
],
"ignorePatterns": [
"!**/*"
],
"overrides": [
{
"files": [
"*.ts",
"*.tsx",
"*.js",
"*.jsx"
],
"rules": {}
},
{
"files": [
"*.ts",
"*.tsx"
],
"rules": {}
},
{
"files": [
"*.js",
"*.jsx"
],
"rules": {}
}
]
}

View File

@@ -0,0 +1,7 @@
# pieces-foreplay-co
This library was generated with [Nx](https://nx.dev).
## Building
Run `nx build pieces-foreplay-co` to build the library.

View File

@@ -0,0 +1,10 @@
{
"name": "@activepieces/piece-foreplay-co",
"version": "0.0.2",
"type": "commonjs",
"main": "./src/index.js",
"types": "./src/index.d.ts",
"dependencies": {
"tslib": "^2.3.0"
}
}

View File

@@ -0,0 +1,65 @@
{
"name": "pieces-foreplay-co",
"$schema": "../../../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "packages/pieces/community/foreplay-co/src",
"projectType": "library",
"release": {
"version": {
"manifestRootsToUpdate": [
"dist/{projectRoot}"
],
"currentVersionResolver": "git-tag",
"fallbackCurrentVersionResolver": "disk"
}
},
"tags": [],
"targets": {
"build": {
"executor": "@nx/js:tsc",
"outputs": [
"{options.outputPath}"
],
"options": {
"outputPath": "dist/packages/pieces/community/foreplay-co",
"tsConfig": "packages/pieces/community/foreplay-co/tsconfig.lib.json",
"packageJson": "packages/pieces/community/foreplay-co/package.json",
"main": "packages/pieces/community/foreplay-co/src/index.ts",
"assets": [
"packages/pieces/community/foreplay-co/*.md",
{
"input": "packages/pieces/community/foreplay-co/src/i18n",
"output": "./src/i18n",
"glob": "**/!(i18n.json)"
}
],
"buildableProjectDepsInPackageJsonType": "dependencies",
"updateBuildableProjectDepsInPackageJson": true
},
"dependsOn": [
"^build",
"prebuild"
]
},
"nx-release-publish": {
"options": {
"packageRoot": "dist/{projectRoot}"
}
},
"lint": {
"executor": "@nx/eslint:lint",
"outputs": [
"{options.outputFile}"
]
},
"prebuild": {
"executor": "nx:run-commands",
"options": {
"cwd": "packages/pieces/community/foreplay-co",
"command": "bun install --no-save --silent"
},
"dependsOn": [
"^build"
]
}
}
}

View File

@@ -0,0 +1,74 @@
{
"Competitive advertising data and creative insights platform. Search, filter, and analyze ads and brands with live and historical ad creatives, metadata, and competitive intelligence.": "Konkurrenzfähige Werbedaten und kreative Einblicke Plattform. Suchen, filtern und analysieren Anzeigen und Marken mit live und historisch anzeigenden, Metadaten und konkurrenzfähiger Intelligenz.",
"Your Foreplay.co API key": "Ihr Foreplay.co API-Schlüssel",
"Get Ad by ID": "Werbung per ID erhalten",
"Get Ads by Page": "Hole Werbung pro Seite",
"Find Brands": "Marken finden",
"Find Ads": "Werbung finden",
"Find Boards": "Foren finden",
"Get detailed information about a specific ad by its ID.": "Erhalten Sie detaillierte Informationen über eine bestimmte Anzeige durch die ID.",
"Get all ads for a Facebook Page ID with filtering and pagination.": "Holen Sie sich alle Anzeigen für eine Facebook-Seiten-ID mit Filterung und Seiteninierung.",
"Search for brands by name with fuzzy matching.": "Suchen Sie nach Marken nach Namen mit verschwommenen Übereinstimmungen.",
"Search and filter ads by text, dates, platforms, and categories.": "Suchen und filtern von Anzeigen nach Text, Datum, Plattformen und Kategorien.",
"Get all boards for the authenticated user with pagination.": "Holen Sie sich alle Boards für den authentifizierten Benutzer mit Seiteninierung.",
"Ad ID": "Ad ID",
"Page ID": "Seiten-ID",
"Start Date": "Startdatum",
"End Date": "Enddatum",
"Order": "Sortierung",
"Live Status": "Live-Status",
"Display Format": "Anzeigeformat",
"Publisher Platform": "Publisher-Plattform",
"Niches": "Nieten",
"Market Target": "Marktziel",
"Languages": "Sprachen",
"Cursor": "Cursor",
"Limit": "Limit",
"Brand Name": "Markenname",
"Search Query": "Suchanfrage",
"Offset": "Versatz",
"The unique identifier of the ad (e.g., \"ad_1234567890\"). You can find this ID from other Foreplay actions or the platform.": "Der eindeutige Identifikator der Anzeige (z.B. \"ad_1234567890\"). Sie können diese ID von anderen Foreplay-Aktionen oder der Plattform finden.",
"The numeric Facebook page ID (e.g., \"123456789\"). You can find this in your Facebook page settings or from other Foreplay actions.": "Die numerische Facebook-Seiten-ID (z.B. \"123456789\"). Du findest diese in deinen Facebook-Einstellungen oder bei anderen Foreplay-Aktionen.",
"Start date (inclusive). Format: YYYY-MM-DD or YYYY-MM-DDTHH:MM:SS": "Startdatum (inklusive). Format: JJJJ-MM-TT oder JJJ-MM-TT-DTHH:MM:SS",
"End date (inclusive). Format: YYYY-MM-DD or YYYY-MM-DDTHH:MM:SS": "Enddatum (inklusive). Format: JJJJ-MM-TT oder JJJ-MM-TT-DTHH:MM:SS",
"Order of results: newest (default), oldest, longest_running, or most_relevant": "Ergebnissortierung: Neueste (Standard), älteste, longest_running oder most_relevant",
"Filter ads by live status. true means currently active ads, false means inactive ads.": "Filtern von Anzeigen nach Live-Status. wahr bedeutet derzeit aktive Werbung, falsch bedeutet inaktive Werbung.",
"Filter by one or more display formats": "Filtern nach einem oder mehreren Anzeigeformaten",
"Filter by one or more publisher platforms": "Filtern nach einer oder mehreren Publisher-Plattformen",
"Filter by one or more niches": "Nach einer oder mehreren Nischen filtern",
"Filter by market target": "Nach Marktziel filtern",
"Filter by languages. Accepts various language formats.": "Nach Sprachen filtern. Akzeptiert verschiedene Sprachformate.",
"Cursor for pagination. Use the cursor value from the previous response.": "Cursor für die Seiteneingabe. Benutzen Sie den Cursor-Wert der vorherigen Antwort.",
"Pagination limit (default 10, max 250). Controls the number of ads returned per request.": "Pagination Limit (Standard 10, max 250). Steuert die Anzahl der Werbung, die pro Anfrage zurückgegeben wird.",
"Brand name to search for (e.g., \"Nike\", \"Apple\"). Supports fuzzy matching for partial names.": "Zu suchender Markenname (z.B. \"Nike\", \"Apple\"). Unterstützt verschwommene Übereinstimmung für Teilnamen.",
"Number of brands to return (max 10).": "Anzahl der zurückzusenden Marken (max 10).",
"Search text for ad name or description. Leave empty to search all ads with filters only.": "Text nach Anzeigenamen oder Beschreibung suchen. Leer lassen, um nur nach Filtern zu suchen.",
"The offset for pagination (default 0).": "Der Versatz für Paginierung (Standard 0).",
"The limit for pagination (default 10, max 10).": "Das Limit für die Paginierung (Standard 10, max 10).",
"Newest": "Neueste",
"Oldest": "Älteste",
"Longest Running": "Längste Laufzeit",
"Most Relevant": "Am relevantesten",
"Active Only": "Nur aktiv",
"Inactive Only": "Nur inaktiv",
"New Ad in Spyder": "Neue Werbung in Spyder",
"New Ad in Board": "Neue Anzeige im Board",
"New Swipefile Ad": "Neue Swipefile Anzeige",
"Triggers when new ads are added for a brand in Spyder.": "Wird ausgelöst, wenn neue Anzeigen für eine Marke in Spyder hinzugefügt werden.",
"Triggers when a new ad is added to the selected board.": "Wird ausgelöst, wenn eine neue Anzeige dem ausgewählten Board hinzugefügt wird.",
"Triggers when a new ad is added to your swipefile collection.": "Wird ausgelöst, wenn eine neue Anzeige zur Sammlung hinzugefügt wird.",
"Brand": "Marke",
"Polling Interval (minutes)": "Umfrageintervall (Minuten)",
"Board": "Brett",
"Select the brand to monitor for new ads.": "Wählen Sie die Marke aus, um neue Anzeigen zu überwachen.",
"How often to check for new ads (in minutes).": "Wie oft wird nach neuen Anzeigen gesucht (in Minuten).",
"Select the board to monitor for new ads.": "Wählen Sie das Board, das für neue Anzeigen überwacht werden soll.",
"Filter ads published after this date.": "Filtern Sie nach diesem Datum veröffentlichte Werbung.",
"Filter ads published before this date.": "Vor diesem Datum veröffentlichte Werbung filtern.",
"Filter by ad status (active/inactive).": "Filtern nach Anzeigenstatus (aktiv/inaktiv).",
"Filter by ad format (video, image, carousel, etc.).": "Filtern nach Anzeigenformat (Video, Bild, Karussell etc.).",
"Filter by platform (Facebook, Instagram, etc.).": "Filtern nach Plattform (Facebook, Instagram, etc.).",
"Filter by industry/category.": "Filtern nach Branche/Kategorie.",
"Filter by target audience (B2B, B2C).": "Filtern nach Zielgruppe (B2B, B2C).",
"Filter by ad language.": "Filtern nach Anzeigensprache."
}

View File

@@ -0,0 +1,74 @@
{
"Competitive advertising data and creative insights platform. Search, filter, and analyze ads and brands with live and historical ad creatives, metadata, and competitive intelligence.": "Los datos publicitarios competitivos y la plataforma de información creativa. Buscar, filtrar y analizar anuncios y marcas con anuncios en vivo e históricos creativos, metadatos e inteligencia competitiva.",
"Your Foreplay.co API key": "Tu clave API de Foreplay.co",
"Get Ad by ID": "Obtener anuncio por ID",
"Get Ads by Page": "Obtener anuncios por página",
"Find Brands": "Buscar marcas",
"Find Ads": "Buscar anuncios",
"Find Boards": "Buscar tableros",
"Get detailed information about a specific ad by its ID.": "Obtenga información detallada sobre un anuncio específico por su ID.",
"Get all ads for a Facebook Page ID with filtering and pagination.": "Obtener todos los anuncios para un ID de página de Facebook con filtrado y paginación.",
"Search for brands by name with fuzzy matching.": "Buscar marcas por nombre con coincidencia difusa.",
"Search and filter ads by text, dates, platforms, and categories.": "Buscar y filtrar anuncios por texto, fechas, plataformas y categorías.",
"Get all boards for the authenticated user with pagination.": "Obtener todos los foros para el usuario autenticado con paginación.",
"Ad ID": "Ad ID",
"Page ID": "ID de página",
"Start Date": "Fecha de inicio",
"End Date": "Fecha de fin",
"Order": "Pedido",
"Live Status": "Estado en vivo",
"Display Format": "Mostrar formato",
"Publisher Platform": "Plataforma de editor",
"Niches": "Nicholas",
"Market Target": "Objetivo de mercado",
"Languages": "Idiomas",
"Cursor": "Cursor",
"Limit": "Límite",
"Brand Name": "Marca",
"Search Query": "Buscar consulta",
"Offset": "Desplazamiento",
"The unique identifier of the ad (e.g., \"ad_1234567890\"). You can find this ID from other Foreplay actions or the platform.": "El identificador único del anuncio (por ejemplo, \"ad_1234567890\"). Puede encontrar este identificador desde otras acciones de la pantalla o la plataforma.",
"The numeric Facebook page ID (e.g., \"123456789\"). You can find this in your Facebook page settings or from other Foreplay actions.": "El ID numérico de la página de Facebook (por ej., \"123456789\"). Puedes encontrarlo en la configuración de tu página de Facebook o en otras acciones para el juego.",
"Start date (inclusive). Format: YYYY-MM-DD or YYYY-MM-DDTHH:MM:SS": "Fecha de inicio (inclusive). Formato: AAA-MM-DD o AAA-MM-DDTHH:MM:SS",
"End date (inclusive). Format: YYYY-MM-DD or YYYY-MM-DDTHH:MM:SS": "Fecha de fin (inclusive). Formato: AAA-MM-DD o AAA-MM-DDTHH:MM:SS",
"Order of results: newest (default), oldest, longest_running, or most_relevant": "Orden de resultados: más reciente (por defecto), más antiguo, más largo_running, o most_relevant",
"Filter ads by live status. true means currently active ads, false means inactive ads.": "Filtrar anuncios por estado real. Verdadero significa anuncios activos, falsos significa anuncios inactivos.",
"Filter by one or more display formats": "Filtrar por uno o más formatos de pantalla",
"Filter by one or more publisher platforms": "Filtrar por una o más plataformas editoriales",
"Filter by one or more niches": "Filtrar por uno o más nicks",
"Filter by market target": "Filtrar por objetivo de mercado",
"Filter by languages. Accepts various language formats.": "Filtrar por idiomas. Acepta varios formatos de idioma.",
"Cursor for pagination. Use the cursor value from the previous response.": "Cursor para la paginación. Utilice el valor del cursor de la respuesta anterior.",
"Pagination limit (default 10, max 250). Controls the number of ads returned per request.": "Límite de paginación (por defecto 10, máx. 250). Controla el número de anuncios devueltos por solicitud.",
"Brand name to search for (e.g., \"Nike\", \"Apple\"). Supports fuzzy matching for partial names.": "Marca de nombre a buscar (por ejemplo, \"Nike\", \"Apple\"). Soporta coincidencia difusa para nombres parciales.",
"Number of brands to return (max 10).": "Número de marcas a devolver (máx. 10).",
"Search text for ad name or description. Leave empty to search all ads with filters only.": "Buscar el nombre o la descripción de los anuncios. Dejar en blanco para buscar todos los anuncios con filtros solamente.",
"The offset for pagination (default 0).": "El desplazamiento para paginación (por defecto 0).",
"The limit for pagination (default 10, max 10).": "El límite de paginación (por defecto 10, máx. 10).",
"Newest": "Más reciente",
"Oldest": "Menos",
"Longest Running": "El más largo en ejecución",
"Most Relevant": "Más relevante",
"Active Only": "Solo Activo",
"Inactive Only": "Solo inactivo",
"New Ad in Spyder": "Nuevo anuncio en Spyder",
"New Ad in Board": "Nuevo anuncio en el foro",
"New Swipefile Ad": "Nuevo anuncio de Swipefile",
"Triggers when new ads are added for a brand in Spyder.": "Dispara cuando se agregan nuevos anuncios para una marca en Spyder.",
"Triggers when a new ad is added to the selected board.": "Se activa cuando se añade un nuevo anuncio al tablero seleccionado.",
"Triggers when a new ad is added to your swipefile collection.": "Se activa cuando se añade un nuevo anuncio a tu colección de archivos de swipefile.",
"Brand": "Marca",
"Polling Interval (minutes)": "Intervalo de encuesta (minutos)",
"Board": "Tablero",
"Select the brand to monitor for new ads.": "Seleccione la marca para monitorizar nuevos anuncios.",
"How often to check for new ads (in minutes).": "Con qué frecuencia comprobar nuevos anuncios (en minutos).",
"Select the board to monitor for new ads.": "Seleccione el tablero para monitorizar nuevos anuncios.",
"Filter ads published after this date.": "Filtrar anuncios publicados después de esta fecha.",
"Filter ads published before this date.": "Filtrar anuncios publicados antes de esta fecha.",
"Filter by ad status (active/inactive).": "Filtrar por estado de anuncio (activo/inactivo).",
"Filter by ad format (video, image, carousel, etc.).": "Filtrar por formato de anuncio (video, imagen, carrusel, etc.).",
"Filter by platform (Facebook, Instagram, etc.).": "Filtrar por plataforma (Facebook, Instagram, etc.).",
"Filter by industry/category.": "Filtrar por industria/categoría.",
"Filter by target audience (B2B, B2C).": "Filtrar por audiencia objetivo (B2B, B2C).",
"Filter by ad language.": "Filtrar por idioma de anuncio."
}

View File

@@ -0,0 +1,74 @@
{
"Competitive advertising data and creative insights platform. Search, filter, and analyze ads and brands with live and historical ad creatives, metadata, and competitive intelligence.": "Des données publicitaires compétitives et des connaissances créatives de la plateforme. Recherchez, filtrez et analysez des publicités et des marques avec des annonces vivantes et historiques, des métadonnées et de l'intelligence concurrentielle.",
"Your Foreplay.co API key": "Votre clé API Foreplay.co",
"Get Ad by ID": "Obtenir une annonce par ID",
"Get Ads by Page": "Recevoir des publicités par page",
"Find Brands": "Trouver des Marques",
"Find Ads": "Trouver des publicités",
"Find Boards": "Trouver des tableaux",
"Get detailed information about a specific ad by its ID.": "Obtenez des informations détaillées sur une annonce spécifique par son ID.",
"Get all ads for a Facebook Page ID with filtering and pagination.": "Obtenez toutes les publicités pour un ID de page Facebook avec filtrage et pagination.",
"Search for brands by name with fuzzy matching.": "Recherchez des marques par nom avec une correspondance floue.",
"Search and filter ads by text, dates, platforms, and categories.": "Rechercher et filtrer les annonces par texte, dates, plateformes et catégories.",
"Get all boards for the authenticated user with pagination.": "Récupère tous les tableaux pour l'utilisateur authentifié avec la pagination.",
"Ad ID": "Ad ID",
"Page ID": "ID de la page",
"Start Date": "Date de début",
"End Date": "Date de fin",
"Order": "Commandes",
"Live Status": "Statut en direct",
"Display Format": "Format d'affichage",
"Publisher Platform": "Plateforme éditrice",
"Niches": "Niches",
"Market Target": "Cible du marché",
"Languages": "Langues",
"Cursor": "Curseur",
"Limit": "Limite",
"Brand Name": "Nom de la marque",
"Search Query": "Requête de recherche",
"Offset": "Décalage",
"The unique identifier of the ad (e.g., \"ad_1234567890\"). You can find this ID from other Foreplay actions or the platform.": "L'identifiant unique de l'annonce (par exemple, \"ad_1234567890\"). Vous pouvez trouver cet ID à partir d'autres actions Foreplay ou de la plateforme.",
"The numeric Facebook page ID (e.g., \"123456789\"). You can find this in your Facebook page settings or from other Foreplay actions.": "L'ID numérique de la page Facebook (par exemple, \"123456789\"). Vous pouvez le trouver dans les paramètres de votre page Facebook ou à partir d'autres actions Foreplay.",
"Start date (inclusive). Format: YYYY-MM-DD or YYYY-MM-DDTHH:MM:SS": "Date de début (inclus). Format: AAAA-MM-JJ ou AAAA-MM-JJJ-AAAA :MM:SS",
"End date (inclusive). Format: YYYY-MM-DD or YYYY-MM-DDTHH:MM:SS": "Date de fin (inclus). Format: AAAA-MM-JJ ou AAAA-MM-JJJH:MM:SS",
"Order of results: newest (default), oldest, longest_running, or most_relevant": "Ordre des résultats : le plus récent (par défaut), le plus ancien, le plus long ou le plus pertinent",
"Filter ads by live status. true means currently active ads, false means inactive ads.": "Filtrer les publicités par statut de live. vrai signifie les publicités actives, faux signifie les publicités inactives.",
"Filter by one or more display formats": "Filtrer par un ou plusieurs formats d'affichage",
"Filter by one or more publisher platforms": "Filtrer par une ou plusieurs plateformes de publication",
"Filter by one or more niches": "Filtrer par une ou plusieurs niches",
"Filter by market target": "Filtrer par cible du marché",
"Filter by languages. Accepts various language formats.": "Filtrer par langue. Accepte les différents formats de langue.",
"Cursor for pagination. Use the cursor value from the previous response.": "Curseur pour la pagination. Utilisez la valeur du curseur de la réponse précédente.",
"Pagination limit (default 10, max 250). Controls the number of ads returned per request.": "Limite de pagination (par défaut 10, max 250). Contrôle le nombre d'annonces retournées par requête.",
"Brand name to search for (e.g., \"Nike\", \"Apple\"). Supports fuzzy matching for partial names.": "Nom de la marque à rechercher (par exemple, \"Nike\", \"Apple\"). Supporte la correspondance floue pour les noms partiels.",
"Number of brands to return (max 10).": "Nombre de marques à retourner (max 10).",
"Search text for ad name or description. Leave empty to search all ads with filters only.": "Rechercher le texte pour le nom ou la description de l'annonce. Laisser vide pour rechercher toutes les annonces avec des filtres seulement.",
"The offset for pagination (default 0).": "Le décalage pour la pagination (par défaut 0).",
"The limit for pagination (default 10, max 10).": "La limite pour la pagination (par défaut 10, max 10).",
"Newest": "Plus récent",
"Oldest": "Plus ancien",
"Longest Running": "La plus longue course",
"Most Relevant": "Le plus pertinent",
"Active Only": "Actif uniquement",
"Inactive Only": "Inactif uniquement",
"New Ad in Spyder": "Nouvelle pub en Spyder",
"New Ad in Board": "Nouvelle pub dans le tableau",
"New Swipefile Ad": "Nouvelle pub Swipefile",
"Triggers when new ads are added for a brand in Spyder.": "Déclenche quand de nouvelles publicités sont ajoutées pour une marque dans Spyder.",
"Triggers when a new ad is added to the selected board.": "Déclenche quand une nouvelle annonce est ajoutée au tableau sélectionné.",
"Triggers when a new ad is added to your swipefile collection.": "Déclenche quand une nouvelle annonce est ajoutée à votre collection de fichiers glissés.",
"Brand": "Marque",
"Polling Interval (minutes)": "Intervalle de vote (minutes)",
"Board": "Tableau",
"Select the brand to monitor for new ads.": "Sélectionnez la marque à surveiller pour les nouvelles annonces.",
"How often to check for new ads (in minutes).": "À quelle fréquence vérifier les nouvelles annonces (en minutes).",
"Select the board to monitor for new ads.": "Sélectionnez le tableau à surveiller pour les nouvelles publicités.",
"Filter ads published after this date.": "Filtrer les annonces publiées après cette date.",
"Filter ads published before this date.": "Filtrer les annonces publiées avant cette date.",
"Filter by ad status (active/inactive).": "Filtrer par statut d'annonce (actif/inactif).",
"Filter by ad format (video, image, carousel, etc.).": "Filtrer par format de publicité (vidéo, image, carrousel, etc.).",
"Filter by platform (Facebook, Instagram, etc.).": "Filtrer par plateforme (Facebook, Instagram, etc.).",
"Filter by industry/category.": "Filtrer par secteur/catégorie.",
"Filter by target audience (B2B, B2C).": "Filtrer par public cible (B2B, B2C).",
"Filter by ad language.": "Filtrer par langue de la publicité."
}

View File

@@ -0,0 +1,74 @@
{
"Competitive advertising data and creative insights platform. Search, filter, and analyze ads and brands with live and historical ad creatives, metadata, and competitive intelligence.": "競争力のある広告データとクリエイティブインサイトプラットフォーム。ライブおよび過去の広告クリエイティブ、メタデータ、および競争力のあるインテリジェンスを使用して、広告やブランドを検索、フィルタリング、分析します。",
"Your Foreplay.co API key": "Foreplay.co API キー",
"Get Ad by ID": "IDで広告を取得",
"Get Ads by Page": "ページで広告を取得する",
"Find Brands": "ブランドを検索",
"Find Ads": "広告を検索",
"Find Boards": "ボードを検索",
"Get detailed information about a specific ad by its ID.": "特定の広告に関する詳細情報をIDで取得します。",
"Get all ads for a Facebook Page ID with filtering and pagination.": "FacebookページIDのすべての広告をフィルタリングとページネーションで取得します。",
"Search for brands by name with fuzzy matching.": "ファジィマッチングでブランドを検索します。",
"Search and filter ads by text, dates, platforms, and categories.": "テキスト、日付、プラットフォーム、カテゴリで広告を検索してフィルタリングします。",
"Get all boards for the authenticated user with pagination.": "ページネーションで認証されたユーザーのすべてのボードを取得します。",
"Ad ID": "Ad ID",
"Page ID": "ページID",
"Start Date": "開始日",
"End Date": "終了日",
"Order": "ご注文",
"Live Status": "ライブ状態",
"Display Format": "表示形式",
"Publisher Platform": "パブリッシャープラットフォーム",
"Niches": "ニッチ文字",
"Market Target": "マーケットターゲット",
"Languages": "言語",
"Cursor": "Cursor",
"Limit": "制限",
"Brand Name": "ブランド名",
"Search Query": "検索クエリ",
"Offset": "オフセット",
"The unique identifier of the ad (e.g., \"ad_1234567890\"). You can find this ID from other Foreplay actions or the platform.": "広告の一意の識別子 (例: \"ad_1234567890\") このIDは、他の前戯アクションまたはプラットフォームから見つけることができます。",
"The numeric Facebook page ID (e.g., \"123456789\"). You can find this in your Facebook page settings or from other Foreplay actions.": "数字のFacebookページID\"123456789\"。これはFacebookページの設定や他の前戯操作で確認できます。",
"Start date (inclusive). Format: YYYY-MM-DD or YYYY-MM-DDTHH:MM:SS": "開始日(含む) フォーマット: YYYY-MM-DD または YYYY-MM-DDTHH:MM:SS",
"End date (inclusive). Format: YYYY-MM-DD or YYYY-MM-DDTHH:MM:SS": "終了日 (含む) 形式: YYYY-MM-DD または YYYY-MM-DDTHH:MM:SS",
"Order of results: newest (default), oldest, longest_running, or most_relevant": "結果の順序最新デフォルト、古い順、longest_running、または最も関連性の高い",
"Filter ads by live status. true means currently active ads, false means inactive ads.": "ライブ状態で広告をフィルターします。trueは現在アクティブな広告を意味し、falseは非アクティブな広告を意味します。",
"Filter by one or more display formats": "1 つ以上の表示形式でフィルター",
"Filter by one or more publisher platforms": "1つ以上のパブリッシャープラットフォームでフィルター",
"Filter by one or more niches": "1つ以上のニッチでフィルター",
"Filter by market target": "マーケットターゲットでフィルター",
"Filter by languages. Accepts various language formats.": "言語で絞り込みます。さまざまな言語フォーマットを利用できます。",
"Cursor for pagination. Use the cursor value from the previous response.": "ページネーションのカーソル。前の応答のカーソルの値を使用します。",
"Pagination limit (default 10, max 250). Controls the number of ads returned per request.": "ページネーション制限 (デフォルト 10、最大 250) リクエストごとに返される広告の数を制御します。",
"Brand name to search for (e.g., \"Nike\", \"Apple\"). Supports fuzzy matching for partial names.": "検索するブランド名(例:Nike, \"Apple\")。部分的な名前の検索に対応しています。",
"Number of brands to return (max 10).": "返品するブランド数最大10。",
"Search text for ad name or description. Leave empty to search all ads with filters only.": "広告名または説明のテキストを検索します。すべての広告をフィルターで検索する場合は空白のままにします。",
"The offset for pagination (default 0).": "ページネーションのオフセット (デフォルト 0)。",
"The limit for pagination (default 10, max 10).": "ページネーションの制限 (デフォルト 10、最大 10)。",
"Newest": "最新",
"Oldest": "古い",
"Longest Running": "最長実行中",
"Most Relevant": "最も関連性の高い",
"Active Only": "アクティブのみ",
"Inactive Only": "非アクティブのみ",
"New Ad in Spyder": "スパイダーの新しい広告",
"New Ad in Board": "新しい広告ボード",
"New Swipefile Ad": "Swipefile広告の新規作成",
"Triggers when new ads are added for a brand in Spyder.": "Spyderのブランドのために新しい広告が追加されたときにトリガー.",
"Triggers when a new ad is added to the selected board.": "選択したボードに新しい広告が追加されたときにトリガーします。",
"Triggers when a new ad is added to your swipefile collection.": "スワイプファイルコレクションに新しい広告が追加されたときにトリガーされます。",
"Brand": "ブランド",
"Polling Interval (minutes)": "ポーリング間隔 (分)",
"Board": "ボード",
"Select the brand to monitor for new ads.": "新しい広告を監視するブランドを選択します。",
"How often to check for new ads (in minutes).": "新しい広告をチェックする頻度(分単位)。",
"Select the board to monitor for new ads.": "新しい広告を監視するボードを選択します。",
"Filter ads published after this date.": "この日付以降に公開された広告をフィルタリングします。",
"Filter ads published before this date.": "この日付以前に公開された広告をフィルタリングします。",
"Filter by ad status (active/inactive).": "広告ステータスでフィルター (アクティブ/非アクティブ)",
"Filter by ad format (video, image, carousel, etc.).": "広告フォーマット(ビデオ、画像、カルーセルなど)でフィルタリングします。",
"Filter by platform (Facebook, Instagram, etc.).": "プラットフォームでフィルター (Facebook、Instagramなど)。",
"Filter by industry/category.": "業界/カテゴリで絞り込みます。",
"Filter by target audience (B2B, B2C).": "ターゲットオーディエンス(B2B、B2C)でフィルタリングします。",
"Filter by ad language.": "広告の言語でフィルタリングします。"
}

View File

@@ -0,0 +1,74 @@
{
"Competitive advertising data and creative insights platform. Search, filter, and analyze ads and brands with live and historical ad creatives, metadata, and competitive intelligence.": "Competitieve reclamegegevens en creatieve inzichten platform. Zoek, filteren en analyseren van advertenties en merken met live en historische advertentie-creatieven, metagegevens en concurrerende intelligentie.",
"Your Foreplay.co API key": "Uw Foreplay.co API-sleutel",
"Get Ad by ID": "Krijg Advertentie via ID",
"Get Ads by Page": "Ontvang advertenties op pagina",
"Find Brands": "Vind Merken",
"Find Ads": "Advertenties zoeken",
"Find Boards": "Vind boards",
"Get detailed information about a specific ad by its ID.": "Krijg gedetailleerde informatie over een specifieke advertentie via zijn ID.",
"Get all ads for a Facebook Page ID with filtering and pagination.": "Download alle advertenties voor een Facebook pagina-ID met filteren en paginering.",
"Search for brands by name with fuzzy matching.": "Zoek naar merken op naam met fuzzy matching.",
"Search and filter ads by text, dates, platforms, and categories.": "Zoek en filter advertenties op tekst, data, platforms en categorieën.",
"Get all boards for the authenticated user with pagination.": "Bekijk alle boards voor de geauthenticeerde gebruiker met paginering.",
"Ad ID": "Ad ID",
"Page ID": "Pagina ID",
"Start Date": "Start datum",
"End Date": "Eind datum",
"Order": "Bestelling",
"Live Status": "Live status",
"Display Format": "Toon formaat",
"Publisher Platform": "Uitgever Platform",
"Niches": "Niches",
"Market Target": "Markt Doel",
"Languages": "Leren",
"Cursor": "Cursor",
"Limit": "Limiet",
"Brand Name": "Merk naam",
"Search Query": "Zoek query",
"Offset": "Verschuiving",
"The unique identifier of the ad (e.g., \"ad_1234567890\"). You can find this ID from other Foreplay actions or the platform.": "De unieke id van de advertentie (bijv. \"ad_1234567890\"). U kunt deze ID vinden uit andere Foreplay acties of het platform.",
"The numeric Facebook page ID (e.g., \"123456789\"). You can find this in your Facebook page settings or from other Foreplay actions.": "De numerieke Facebook pagina ID (bijv. \"123456789\"). U kunt dit vinden in uw Facebook pagina instellingen of in andere Foreplay acties.",
"Start date (inclusive). Format: YYYY-MM-DD or YYYY-MM-DDTHH:MM:SS": "Startdatum (inclusief). Formaat: JJJJ-MM-DD of JJJJ-MM-DDTHH:MM:SS",
"End date (inclusive). Format: YYYY-MM-DD or YYYY-MM-DDTHH:MM:SS": "Einddatum (inclusief). Formaat: JJJJ-MM-DD of JJJJ-MM-DDTHH:MM:SS",
"Order of results: newest (default), oldest, longest_running, or most_relevant": "Volgorde van resultaten: nieuwste (standaard), oldest, langst_running, of most_relevant",
"Filter ads by live status. true means currently active ads, false means inactive ads.": "Advertenties filteren op live status. Waar zijn momenteel actieve advertenties, onwaar betekent inactieve advertenties.",
"Filter by one or more display formats": "Filter op één of meer formaten",
"Filter by one or more publisher platforms": "Filter op één of meerdere publisher platforms",
"Filter by one or more niches": "Filter op één of meer niches",
"Filter by market target": "Filter op marktdoel",
"Filter by languages. Accepts various language formats.": "Filter op talen. Accepteert verschillende taalformaten.",
"Cursor for pagination. Use the cursor value from the previous response.": "Cursor voor paginering. Gebruik de cursor waarde van de vorige reactie.",
"Pagination limit (default 10, max 250). Controls the number of ads returned per request.": "Paginering limiet (standaard 10, max 250). Bepaalt het aantal terugkerende advertenties per verzoek.",
"Brand name to search for (e.g., \"Nike\", \"Apple\"). Supports fuzzy matching for partial names.": "Merk naam om naar te zoeken (bijv. \"Nike\", \"Apple\"). Ondersteunt fuzzy matching voor partiële namen.",
"Number of brands to return (max 10).": "Aantal merken om terug te keren (max 10).",
"Search text for ad name or description. Leave empty to search all ads with filters only.": "Zoek tekst voor advertentienaam of beschrijving. Laat leeg om alleen alle advertenties met filters te doorzoeken.",
"The offset for pagination (default 0).": "De offset voor paginering (standaard 0).",
"The limit for pagination (default 10, max 10).": "De limiet voor paginering (standaard 10, max 10).",
"Newest": "Nieuwste",
"Oldest": "Oudste",
"Longest Running": "Langste actieve",
"Most Relevant": "Meest relevante",
"Active Only": "Alleen actief",
"Inactive Only": "Alleen inactief",
"New Ad in Spyder": "Nieuwe advertentie in spyder",
"New Ad in Board": "Nieuwe advertentie in bord",
"New Swipefile Ad": "Nieuwe Swipiefile Advertentie",
"Triggers when new ads are added for a brand in Spyder.": "Triggert wanneer nieuwe advertenties worden toegevoegd voor een merk in Spyder.",
"Triggers when a new ad is added to the selected board.": "Triggert wanneer een nieuwe advertentie wordt toegevoegd aan het geselecteerde bord.",
"Triggers when a new ad is added to your swipefile collection.": "Triggert wanneer een nieuwe advertentie wordt toegevoegd aan je swipefile collectie.",
"Brand": "Merk",
"Polling Interval (minutes)": "Polling Interval (minuten)",
"Board": "Bord",
"Select the brand to monitor for new ads.": "Selecteer het merk om te monitoren voor nieuwe advertenties.",
"How often to check for new ads (in minutes).": "Hoe vaak te controleren op nieuwe advertenties (in minuten).",
"Select the board to monitor for new ads.": "Selecteer het bord om te monitoren voor nieuwe advertenties.",
"Filter ads published after this date.": "Filter advertenties gepubliceerd na deze datum.",
"Filter ads published before this date.": "Filter advertenties gepubliceerd voor deze datum.",
"Filter by ad status (active/inactive).": "Filter op advertentie-status (actief/inactief).",
"Filter by ad format (video, image, carousel, etc.).": "Filter op advertentie-formaat (video, afbeelding, carousel, enz.).",
"Filter by platform (Facebook, Instagram, etc.).": "Filter op platform (Facebook, Instagram, etc.).",
"Filter by industry/category.": "Filteren op industrie/categorie.",
"Filter by target audience (B2B, B2C).": "Filter op doelgroep (B2B, B2C).",
"Filter by ad language.": "Filter op advertentie taal."
}

View File

@@ -0,0 +1,74 @@
{
"Competitive advertising data and creative insights platform. Search, filter, and analyze ads and brands with live and historical ad creatives, metadata, and competitive intelligence.": "Dados competitivos de publicidade e ideias criativas. Pesquise, filtre e analise anúncios e marcas com criadores de anúncios ao vivo e histórico, metadados e inteligência competitiva.",
"Your Foreplay.co API key": "Sua chave de API do Foreplay.co",
"Get Ad by ID": "Obter anúncio pelo ID",
"Get Ads by Page": "Receba anúncios por página",
"Find Brands": "Encontrar Marcas",
"Find Ads": "Encontrar anúncios",
"Find Boards": "Encontrar Quadros",
"Get detailed information about a specific ad by its ID.": "Obtenha informações detalhadas sobre um anúncio específico por seu ID.",
"Get all ads for a Facebook Page ID with filtering and pagination.": "Obtenha todos os anúncios para um ID de Página do Facebook com filtragem e paginação.",
"Search for brands by name with fuzzy matching.": "Pesquise marcas por nome com correspondência incerta.",
"Search and filter ads by text, dates, platforms, and categories.": "Pesquisar e filtrar anúncios por texto, datas, plataformas e categorias.",
"Get all boards for the authenticated user with pagination.": "Obtenha todos os quadros para o usuário autenticado com paginação.",
"Ad ID": "Ad ID",
"Page ID": "ID da Página",
"Start Date": "Data Inicial",
"End Date": "Data de Término",
"Order": "Encomenda",
"Live Status": "Status ao vivo",
"Display Format": "Formato de Exibição",
"Publisher Platform": "Plataforma de Publicação",
"Niches": "Nichos",
"Market Target": "Alvo do Mercado",
"Languages": "Idiomas",
"Cursor": "Cursor",
"Limit": "Limitar",
"Brand Name": "Nome da Marca",
"Search Query": "Consulta de Pesquisa",
"Offset": "Deslocamento",
"The unique identifier of the ad (e.g., \"ad_1234567890\"). You can find this ID from other Foreplay actions or the platform.": "O identificador exclusivo do anúncio (por exemplo, \"ad_1234567890\"). Você pode encontrar esse ID em outras ações do Foreplay ou na plataforma.",
"The numeric Facebook page ID (e.g., \"123456789\"). You can find this in your Facebook page settings or from other Foreplay actions.": "A ID de página numérica do Facebook (ex: \"123456789\"). Você pode encontrar isso nas configurações da sua página do Facebook ou de outras ações do Foreplay.",
"Start date (inclusive). Format: YYYY-MM-DD or YYYY-MM-DDTHH:MM:SS": "Data de início (inclusive). Formato: YYYY-MM-DD ou YYYY-MM-DDTHH:MM:SS",
"End date (inclusive). Format: YYYY-MM-DD or YYYY-MM-DDTHH:MM:SS": "Data final (inclusive). Formato: YYYY-MM-DD ou YYYY-MM-DDTHH:MM:SS",
"Order of results: newest (default), oldest, longest_running, or most_relevant": "Ordem dos resultados: mais recente (padrão), mais antigo, mais longínquo ou mais relevante",
"Filter ads by live status. true means currently active ads, false means inactive ads.": "Filtrar anúncios por estado vivo. verdadeiro significa anúncios ativos atualmente, falso significa anúncios inativos.",
"Filter by one or more display formats": "Filtrar por um ou mais formatos de exibição",
"Filter by one or more publisher platforms": "Filtrar por uma ou mais plataformas de editor",
"Filter by one or more niches": "Filtrar por um ou mais nichos",
"Filter by market target": "Filtrar por alvo de mercado",
"Filter by languages. Accepts various language formats.": "Filtrar por idiomas. Aceita vários formatos de idioma.",
"Cursor for pagination. Use the cursor value from the previous response.": "Cursor para paginação. Use o valor do cursor da resposta anterior.",
"Pagination limit (default 10, max 250). Controls the number of ads returned per request.": "Limite de paginação (padrão 10, max 250). Controla o número de anúncios retornados por solicitação.",
"Brand name to search for (e.g., \"Nike\", \"Apple\"). Supports fuzzy matching for partial names.": "Nome da marca para procurar (por exemplo, \"Nike\", \"Apple\"). Suporta correspondência incerta para nomes parciais.",
"Number of brands to return (max 10).": "Número de marcas a retornar (máx. 10).",
"Search text for ad name or description. Leave empty to search all ads with filters only.": "Pesquisar texto para nome do anúncio ou descrição. Deixe em branco para pesquisar todos os anúncios com filtros apenas.",
"The offset for pagination (default 0).": "O deslocamento para paginação (padrão 0).",
"The limit for pagination (default 10, max 10).": "O limite para a paginação (padrão 10, max 10).",
"Newest": "Recentes",
"Oldest": "Antigos",
"Longest Running": "Corrida mais longa",
"Most Relevant": "Mais relevante",
"Active Only": "Somente ativo",
"Inactive Only": "Apenas inativo",
"New Ad in Spyder": "Novo anúncio no Spyder",
"New Ad in Board": "Novo anúncio no board",
"New Swipefile Ad": "Anúncio de Novo Swipefile",
"Triggers when new ads are added for a brand in Spyder.": "Aciona quando novos anúncios são adicionados para uma marca no Spyder.",
"Triggers when a new ad is added to the selected board.": "Dispara quando um novo anúncio é adicionado ao quadro selecionado.",
"Triggers when a new ad is added to your swipefile collection.": "Aciona quando um novo anúncio é adicionado à sua coleção de arquivos deslizantes.",
"Brand": "Bandeira",
"Polling Interval (minutes)": "Intervalo de votação (minutos)",
"Board": "Tabuleiro",
"Select the brand to monitor for new ads.": "Selecione a marca para monitorar novos anúncios.",
"How often to check for new ads (in minutes).": "Com que frequência verificar se há anúncios novos (em minutos).",
"Select the board to monitor for new ads.": "Selecione o board para monitorar novos anúncios.",
"Filter ads published after this date.": "Filtrar anúncios publicados após esta data.",
"Filter ads published before this date.": "Filtrar anúncios publicados antes desta data.",
"Filter by ad status (active/inactive).": "Filtrar por estado do anúncio (ativo/inativo).",
"Filter by ad format (video, image, carousel, etc.).": "Filtrar por formato de anúncio (vídeo, imagem, carrossel, etc.).",
"Filter by platform (Facebook, Instagram, etc.).": "Filtrar pela plataforma (Facebook, Instagram, etc.).",
"Filter by industry/category.": "Filtrar por indústria/categoria.",
"Filter by target audience (B2B, B2C).": "Filtrar por público-alvo (B2B, B2C).",
"Filter by ad language.": "Filtrar por idioma de anúncio."
}

View File

@@ -0,0 +1,74 @@
{
"Competitive advertising data and creative insights platform. Search, filter, and analyze ads and brands with live and historical ad creatives, metadata, and competitive intelligence.": "Competitive advertising data and creative insights platform. Search, filter, and analyze ads and brands with live and historical ad creatives, metadata, and competitive intelligence.",
"Your Foreplay.co API key": "Your Foreplay.co API key",
"Get Ad by ID": "Get Ad by ID",
"Get Ads by Page": "Get Ads by Page",
"Find Brands": "Find Brands",
"Find Ads": "Find Ads",
"Find Boards": "Find Boards",
"Get detailed information about a specific ad by its ID.": "Get detailed information about a specific ad by its ID.",
"Get all ads for a Facebook Page ID with filtering and pagination.": "Get all ads for a Facebook Page ID with filtering and pagination.",
"Search for brands by name with fuzzy matching.": "Search for brands by name with fuzzy matching.",
"Search and filter ads by text, dates, platforms, and categories.": "Search and filter ads by text, dates, platforms, and categories.",
"Get all boards for the authenticated user with pagination.": "Get all boards for the authenticated user with pagination.",
"Ad ID": "Ad ID",
"Page ID": "Page ID",
"Start Date": "Start Date",
"End Date": "End Date",
"Order": "Order",
"Live Status": "Live Status",
"Display Format": "Display Format",
"Publisher Platform": "Publisher Platform",
"Niches": "Niches",
"Market Target": "Market Target",
"Languages": "Languages",
"Cursor": "Cursor",
"Limit": "Limit",
"Brand Name": "Brand Name",
"Search Query": "Search Query",
"Offset": "Offset",
"The unique identifier of the ad (e.g., \"ad_1234567890\"). You can find this ID from other Foreplay actions or the platform.": "The unique identifier of the ad (e.g., \"ad_1234567890\"). You can find this ID from other Foreplay actions or the platform.",
"The numeric Facebook page ID (e.g., \"123456789\"). You can find this in your Facebook page settings or from other Foreplay actions.": "The numeric Facebook page ID (e.g., \"123456789\"). You can find this in your Facebook page settings or from other Foreplay actions.",
"Start date (inclusive). Format: YYYY-MM-DD or YYYY-MM-DDTHH:MM:SS": "Start date (inclusive). Format: YYYY-MM-DD or YYYY-MM-DDTHH:MM:SS",
"End date (inclusive). Format: YYYY-MM-DD or YYYY-MM-DDTHH:MM:SS": "End date (inclusive). Format: YYYY-MM-DD or YYYY-MM-DDTHH:MM:SS",
"Order of results: newest (default), oldest, longest_running, or most_relevant": "Order of results: newest (default), oldest, longest_running, or most_relevant",
"Filter ads by live status. true means currently active ads, false means inactive ads.": "Filter ads by live status. true means currently active ads, false means inactive ads.",
"Filter by one or more display formats": "Filter by one or more display formats",
"Filter by one or more publisher platforms": "Filter by one or more publisher platforms",
"Filter by one or more niches": "Filter by one or more niches",
"Filter by market target": "Filter by market target",
"Filter by languages. Accepts various language formats.": "Filter by languages. Accepts various language formats.",
"Cursor for pagination. Use the cursor value from the previous response.": "Cursor for pagination. Use the cursor value from the previous response.",
"Pagination limit (default 10, max 250). Controls the number of ads returned per request.": "Pagination limit (default 10, max 250). Controls the number of ads returned per request.",
"Brand name to search for (e.g., \"Nike\", \"Apple\"). Supports fuzzy matching for partial names.": "Brand name to search for (e.g., \"Nike\", \"Apple\"). Supports fuzzy matching for partial names.",
"Number of brands to return (max 10).": "Number of brands to return (max 10).",
"Search text for ad name or description. Leave empty to search all ads with filters only.": "Search text for ad name or description. Leave empty to search all ads with filters only.",
"The offset for pagination (default 0).": "The offset for pagination (default 0).",
"The limit for pagination (default 10, max 10).": "The limit for pagination (default 10, max 10).",
"Newest": "Newest",
"Oldest": "Oldest",
"Longest Running": "Longest Running",
"Most Relevant": "Most Relevant",
"Active Only": "Active Only",
"Inactive Only": "Inactive Only",
"New Ad in Spyder": "New Ad in Spyder",
"New Ad in Board": "New Ad in Board",
"New Swipefile Ad": "New Swipefile Ad",
"Triggers when new ads are added for a brand in Spyder.": "Triggers when new ads are added for a brand in Spyder.",
"Triggers when a new ad is added to the selected board.": "Triggers when a new ad is added to the selected board.",
"Triggers when a new ad is added to your swipefile collection.": "Triggers when a new ad is added to your swipefile collection.",
"Brand": "Brand",
"Polling Interval (minutes)": "Polling Interval (minutes)",
"Board": "Board",
"Select the brand to monitor for new ads.": "Select the brand to monitor for new ads.",
"How often to check for new ads (in minutes).": "How often to check for new ads (in minutes).",
"Select the board to monitor for new ads.": "Select the board to monitor for new ads.",
"Filter ads published after this date.": "Filter ads published after this date.",
"Filter ads published before this date.": "Filter ads published before this date.",
"Filter by ad status (active/inactive).": "Filter by ad status (active/inactive).",
"Filter by ad format (video, image, carousel, etc.).": "Filter by ad format (video, image, carousel, etc.).",
"Filter by platform (Facebook, Instagram, etc.).": "Filter by platform (Facebook, Instagram, etc.).",
"Filter by industry/category.": "Filter by industry/category.",
"Filter by target audience (B2B, B2C).": "Filter by target audience (B2B, B2C).",
"Filter by ad language.": "Filter by ad language."
}

View File

@@ -0,0 +1,74 @@
{
"Competitive advertising data and creative insights platform. Search, filter, and analyze ads and brands with live and historical ad creatives, metadata, and competitive intelligence.": "Competitive advertising data and creative insights platform. Search, filter, and analyze ads and brands with live and historical ad creatives, metadata, and competitive intelligence.",
"Your Foreplay.co API key": "Your Foreplay.co API key",
"Get Ad by ID": "Get Ad by ID",
"Get Ads by Page": "Get Ads by Page",
"Find Brands": "Find Brands",
"Find Ads": "Find Ads",
"Find Boards": "Find Boards",
"Get detailed information about a specific ad by its ID.": "Get detailed information about a specific ad by its ID.",
"Get all ads for a Facebook Page ID with filtering and pagination.": "Get all ads for a Facebook Page ID with filtering and pagination.",
"Search for brands by name with fuzzy matching.": "Search for brands by name with fuzzy matching.",
"Search and filter ads by text, dates, platforms, and categories.": "Search and filter ads by text, dates, platforms, and categories.",
"Get all boards for the authenticated user with pagination.": "Get all boards for the authenticated user with pagination.",
"Ad ID": "Ad ID",
"Page ID": "Page ID",
"Start Date": "Start Date",
"End Date": "End Date",
"Order": "Order",
"Live Status": "Live Status",
"Display Format": "Display Format",
"Publisher Platform": "Publisher Platform",
"Niches": "Niches",
"Market Target": "Market Target",
"Languages": "Languages",
"Cursor": "Cursor",
"Limit": "Limit",
"Brand Name": "Brand Name",
"Search Query": "Search Query",
"Offset": "Offset",
"The unique identifier of the ad (e.g., \"ad_1234567890\"). You can find this ID from other Foreplay actions or the platform.": "The unique identifier of the ad (e.g., \"ad_1234567890\"). You can find this ID from other Foreplay actions or the platform.",
"The numeric Facebook page ID (e.g., \"123456789\"). You can find this in your Facebook page settings or from other Foreplay actions.": "The numeric Facebook page ID (e.g., \"123456789\"). You can find this in your Facebook page settings or from other Foreplay actions.",
"Start date (inclusive). Format: YYYY-MM-DD or YYYY-MM-DDTHH:MM:SS": "Start date (inclusive). Format: YYYY-MM-DD or YYYY-MM-DDTHH:MM:SS",
"End date (inclusive). Format: YYYY-MM-DD or YYYY-MM-DDTHH:MM:SS": "End date (inclusive). Format: YYYY-MM-DD or YYYY-MM-DDTHH:MM:SS",
"Order of results: newest (default), oldest, longest_running, or most_relevant": "Order of results: newest (default), oldest, longest_running, or most_relevant",
"Filter ads by live status. true means currently active ads, false means inactive ads.": "Filter ads by live status. true means currently active ads, false means inactive ads.",
"Filter by one or more display formats": "Filter by one or more display formats",
"Filter by one or more publisher platforms": "Filter by one or more publisher platforms",
"Filter by one or more niches": "Filter by one or more niches",
"Filter by market target": "Filter by market target",
"Filter by languages. Accepts various language formats.": "Filter by languages. Accepts various language formats.",
"Cursor for pagination. Use the cursor value from the previous response.": "Cursor for pagination. Use the cursor value from the previous response.",
"Pagination limit (default 10, max 250). Controls the number of ads returned per request.": "Pagination limit (default 10, max 250). Controls the number of ads returned per request.",
"Brand name to search for (e.g., \"Nike\", \"Apple\"). Supports fuzzy matching for partial names.": "Brand name to search for (e.g., \"Nike\", \"Apple\"). Supports fuzzy matching for partial names.",
"Number of brands to return (max 10).": "Number of brands to return (max 10).",
"Search text for ad name or description. Leave empty to search all ads with filters only.": "Search text for ad name or description. Leave empty to search all ads with filters only.",
"The offset for pagination (default 0).": "The offset for pagination (default 0).",
"The limit for pagination (default 10, max 10).": "The limit for pagination (default 10, max 10).",
"Newest": "Newest",
"Oldest": "Oldest",
"Longest Running": "Longest Running",
"Most Relevant": "Most Relevant",
"Active Only": "Active Only",
"Inactive Only": "Inactive Only",
"New Ad in Spyder": "New Ad in Spyder",
"New Ad in Board": "New Ad in Board",
"New Swipefile Ad": "New Swipefile Ad",
"Triggers when new ads are added for a brand in Spyder.": "Triggers when new ads are added for a brand in Spyder.",
"Triggers when a new ad is added to the selected board.": "Triggers when a new ad is added to the selected board.",
"Triggers when a new ad is added to your swipefile collection.": "Triggers when a new ad is added to your swipefile collection.",
"Brand": "Brand",
"Polling Interval (minutes)": "Polling Interval (minutes)",
"Board": "Board",
"Select the brand to monitor for new ads.": "Select the brand to monitor for new ads.",
"How often to check for new ads (in minutes).": "How often to check for new ads (in minutes).",
"Select the board to monitor for new ads.": "Select the board to monitor for new ads.",
"Filter ads published after this date.": "Filter ads published after this date.",
"Filter ads published before this date.": "Filter ads published before this date.",
"Filter by ad status (active/inactive).": "Filter by ad status (active/inactive).",
"Filter by ad format (video, image, carousel, etc.).": "Filter by ad format (video, image, carousel, etc.).",
"Filter by platform (Facebook, Instagram, etc.).": "Filter by platform (Facebook, Instagram, etc.).",
"Filter by industry/category.": "Filter by industry/category.",
"Filter by target audience (B2B, B2C).": "Filter by target audience (B2B, B2C).",
"Filter by ad language.": "Filter by ad language."
}

View File

@@ -0,0 +1,23 @@
import { createPiece, PieceAuth } from "@activepieces/pieces-framework";
import { PieceCategory } from "@activepieces/shared";
import { getAdById, getAdsByPage, findBrands, findAds, findBoards } from "./lib/actions";
import { newAdInSpyder, newAdInBoard, newSwipefileAd } from "./lib/triggers";
export const foreplayCoAuth = PieceAuth.SecretText({
displayName: "API Key",
description: "Your Foreplay.co API key",
required: true,
})
export const foreplayCo = createPiece({
displayName: "Foreplay",
description: "Competitive advertising data and creative insights platform. Search, filter, and analyze ads and brands with live and historical ad creatives, metadata, and competitive intelligence.",
auth: foreplayCoAuth,
minimumSupportedRelease: '0.36.1',
logoUrl: "https://cdn.activepieces.com/pieces/foreplay-co.png",
categories: [PieceCategory.MARKETING],
authors: ['fortunamide', 'onyedikachi-david'],
actions: [getAdById, getAdsByPage, findBrands, findAds, findBoards],
triggers: [newAdInSpyder, newAdInBoard, newSwipefileAd],
});

View File

@@ -0,0 +1,108 @@
import { createAction } from '@activepieces/pieces-framework';
import { foreplayCoApiCall } from '../common';
import { HttpMethod } from '@activepieces/pieces-common';
import { findAds as findAdsProperties } from '../properties';
import { findAdsSchema } from '../schemas';
import { foreplayCoAuth } from '../..';
export const findAds = createAction({
auth: foreplayCoAuth,
name: 'findAds',
displayName: 'Find Ads',
description:
'Search and filter ads by text, dates, platforms, and categories.',
props: findAdsProperties(),
async run({ auth, propsValue }) {
// Validate props using Zod schema
const validation = findAdsSchema.safeParse(propsValue);
if (!validation.success) {
throw new Error(`Validation failed: ${validation.error.message}`);
}
const values = propsValue;
// Build query parameters properly handling arrays for API
const queryParams = new URLSearchParams();
// Add optional parameters if provided
if (values['query']) {
queryParams.append('query', String(values['query']));
}
if (values['start_date']) {
queryParams.append('start_date', String(values['start_date']));
}
if (values['end_date']) {
queryParams.append('end_date', String(values['end_date']));
}
if (values['order']) {
queryParams.append('order', String(values['order']));
}
if (values['live']) {
queryParams.append('live', String(values['live']));
}
// Handle array parameters - repeat parameter name for each value
if (values['display_format'] && values['display_format'].length > 0) {
values['display_format'].forEach((format: unknown) => {
queryParams.append('display_format', String(format));
});
}
if (
values['publisher_platform'] &&
values['publisher_platform'].length > 0
) {
values['publisher_platform'].forEach((platform: unknown) => {
queryParams.append('publisher_platform', String(platform));
});
}
if (values['niches'] && values['niches'].length > 0) {
values['niches'].forEach((niche: unknown) => {
queryParams.append('niches', String(niche));
});
}
if (values['market_target'] && values['market_target'].length > 0) {
values['market_target'].forEach((target: unknown) => {
queryParams.append('market_target', String(target));
});
}
if (values['languages'] && values['languages'].length > 0) {
values['languages'].forEach((language: unknown) => {
queryParams.append('languages', String(language));
});
}
if (values['cursor']) {
queryParams.append('cursor', String(values['cursor']));
}
if (values['limit']) {
queryParams.append('limit', String(values['limit']));
}
// Build the full URL with query parameters manually to handle arrays properly
const queryString = queryParams.toString();
const fullUrl = queryString
? `/api/discovery/ads?${queryString}`
: '/api/discovery/ads';
const response = await foreplayCoApiCall({
apiKey: auth,
method: HttpMethod.GET,
resourceUri: fullUrl,
});
const responseBody = response.body;
// Check if the response is successful
if (responseBody.metadata && responseBody.metadata.success === true) {
// Return just the ads data for clean automation workflows
return responseBody.data;
} else {
// Handle error responses by throwing an error
const errorMessage =
responseBody.error ||
responseBody.metadata?.message ||
'Failed to find ads';
throw new Error(`Foreplay.co API Error: ${errorMessage}`);
}
},
});

View File

@@ -0,0 +1,54 @@
import { createAction } from '@activepieces/pieces-framework';
import { foreplayCoApiCall } from '../common';
import { HttpMethod } from '@activepieces/pieces-common';
import { findBoards as findBoardsProperties } from '../properties';
import { findBoardsSchema } from '../schemas';
import { foreplayCoAuth } from '../..';
export const findBoards = createAction({
name: 'findBoards',
displayName: 'Find Boards',
description: 'Get all boards for the authenticated user with pagination.',
props: findBoardsProperties(),
auth: foreplayCoAuth,
async run({ auth, propsValue }) {
// Validate props using Zod schema
const validation = findBoardsSchema.safeParse(propsValue);
if (!validation.success) {
throw new Error(`Validation failed: ${validation.error.message}`);
}
const values = propsValue;
const queryParams: Record<string, string> = {};
// Add optional parameters if provided
if (values['offset'] !== undefined) {
queryParams['offset'] = String(values['offset']);
}
if (values['limit'] !== undefined) {
queryParams['limit'] = String(values['limit']);
}
const response = await foreplayCoApiCall({
apiKey: auth,
method: HttpMethod.GET,
resourceUri: '/api/boards',
queryParams,
});
const responseBody = response.body;
// Check if the response is successful
if (responseBody.metadata && responseBody.metadata.success === true) {
// Return just the boards data for clean automation workflows
return responseBody.data;
} else {
// Handle error responses by throwing an error
const errorMessage =
responseBody.error ||
responseBody.metadata?.message ||
'Failed to retrieve boards';
throw new Error(`Foreplay.co API Error: ${errorMessage}`);
}
},
});

View File

@@ -0,0 +1,53 @@
import { createAction } from '@activepieces/pieces-framework';
import { foreplayCoApiCall } from '../common';
import { HttpMethod } from '@activepieces/pieces-common';
import { findBrands as findBrandsProperties } from '../properties';
import { findBrandsSchema } from '../schemas';
import { foreplayCoAuth } from '../..';
export const findBrands = createAction({
name: 'findBrands',
displayName: 'Find Brands',
description: 'Search for brands by name with fuzzy matching.',
props: findBrandsProperties(),
auth: foreplayCoAuth,
async run({ auth, propsValue }) {
// Validate props using Zod schema
const validation = findBrandsSchema.safeParse(propsValue);
if (!validation.success) {
throw new Error(`Validation failed: ${validation.error.message}`);
}
const values = propsValue;
const queryParams: Record<string, string> = {
query: String(values['query']),
};
// Add optional limit parameter if provided
if (values['limit']) {
queryParams['limit'] = String(values['limit']);
}
const response = await foreplayCoApiCall({
apiKey: auth,
method: HttpMethod.GET,
resourceUri: '/api/discovery/brands',
queryParams,
});
const responseBody = response.body;
// Check if the response is successful
if (responseBody.metadata && responseBody.metadata.success === true) {
// Return just the brands data for clean automation workflows
return responseBody.data;
} else {
// Handle error responses by throwing an error
const errorMessage =
responseBody.error ||
responseBody.metadata?.message ||
'Failed to find brands';
throw new Error(`Foreplay.co API Error: ${errorMessage}`);
}
},
});

View File

@@ -0,0 +1,44 @@
import { createAction } from '@activepieces/pieces-framework';
import { foreplayCoApiCall } from '../common';
import { HttpMethod } from '@activepieces/pieces-common';
import { getAdById as getAdByIdProperties } from '../properties';
import { getAdByIdSchema } from '../schemas';
import { foreplayCoAuth } from '../..';
export const getAdById = createAction({
name: 'getAdById',
displayName: 'Get Ad by ID',
description: 'Get detailed information about a specific ad by its ID.',
props: getAdByIdProperties(),
auth: foreplayCoAuth,
async run({ auth, propsValue }) {
// Validate props using Zod schema
const validation = getAdByIdSchema.safeParse(propsValue);
if (!validation.success) {
throw new Error(`Validation failed: ${validation.error.message}`);
}
const adId = propsValue.ad_id;
const response = await foreplayCoApiCall({
apiKey: auth,
method: HttpMethod.GET,
resourceUri: `/api/ad/${adId}`,
});
const responseBody = response.body;
// Check if the response is successful
if (responseBody.metadata && responseBody.metadata.success === true) {
// Return just the ad data for clean automation workflows
return responseBody.data;
} else {
// Handle error responses by throwing an error
const errorMessage =
responseBody.error ||
responseBody.metadata?.message ||
'Failed to retrieve ad';
throw new Error(`Foreplay.co API Error: ${errorMessage}`);
}
},
});

View File

@@ -0,0 +1,103 @@
import { createAction } from '@activepieces/pieces-framework';
import { foreplayCoApiCall } from '../common';
import { HttpMethod } from '@activepieces/pieces-common';
import { getAdsByPage as getAdsByPageProperties } from '../properties';
import { getAdsByPageSchema } from '../schemas';
import { foreplayCoAuth } from '../..';
export const getAdsByPage = createAction({
name: 'getAdsByPage',
displayName: 'Get Ads by Page',
description:
'Get all ads for a Facebook Page ID with filtering and pagination.',
props: getAdsByPageProperties(),
auth: foreplayCoAuth,
async run({ auth, propsValue }) {
// Validate props using Zod schema
const validation = getAdsByPageSchema.safeParse(propsValue);
if (!validation.success) {
throw new Error(`Validation failed: ${validation.error.message}`);
}
const values = propsValue;
// Build query parameters properly handling arrays for API
const queryParams = new URLSearchParams();
queryParams.append('page_id', String(values.page_id));
// Add optional parameters if provided
if (values.start_date) {
queryParams.append('start_date', String(values.start_date));
}
if (values.end_date) {
queryParams.append('end_date', String(values.end_date));
}
if (values.order) {
queryParams.append('order', String(values.order));
}
if (values.live) {
queryParams.append('live', String(values.live));
}
// Handle array parameters - repeat parameter name for each value
if (values.display_format && values.display_format.length > 0) {
values.display_format.forEach((format: unknown) => {
queryParams.append('display_format', String(format));
});
}
if (values.publisher_platform && values.publisher_platform.length > 0) {
values.publisher_platform.forEach((platform: unknown) => {
queryParams.append('publisher_platform', String(platform));
});
}
if (values.niches && values.niches.length > 0) {
values.niches.forEach((niche: unknown) => {
queryParams.append('niches', String(niche));
});
}
if (values.market_target && values.market_target.length > 0) {
values.market_target.forEach((target: unknown) => {
queryParams.append('market_target', String(target));
});
}
if (values.languages && values.languages.length > 0) {
values.languages.forEach((language: unknown) => {
queryParams.append('languages', String(language));
});
}
if (values.cursor) {
queryParams.append('cursor', String(values.cursor));
}
if (values.limit) {
queryParams.append('limit', String(values.limit));
}
// Build the full URL with query parameters manually to handle arrays properly
const queryString = queryParams.toString();
const fullUrl = queryString
? `/api/brand/getAdsByPageId?${queryString}`
: '/api/brand/getAdsByPageId';
const response = await foreplayCoApiCall({
apiKey: auth,
method: HttpMethod.GET,
resourceUri: fullUrl,
});
const responseBody = response.body;
// Check if the response is successful
if (responseBody.metadata && responseBody.metadata.success === true) {
// Return just the ads data for clean automation workflows
return responseBody.data;
} else {
// Handle error responses by throwing an error
const errorMessage =
responseBody.error ||
responseBody.metadata?.message ||
'Failed to retrieve ads for page';
throw new Error(`Foreplay.co API Error: ${errorMessage}`);
}
},
});

View File

@@ -0,0 +1,5 @@
export { getAdById } from './get-ad-by-id';
export { getAdsByPage } from './get-ads-by-page';
export { findBrands } from './find-brands';
export { findAds } from './find-ads';
export { findBoards } from './find-boards';

View File

@@ -0,0 +1,32 @@
import { httpClient, HttpMethod, AuthenticationType } from "@activepieces/pieces-common";
import { AppConnectionValueForAuthProperty } from "@activepieces/pieces-framework";
import { foreplayCoAuth } from "..";
export interface ForeplayCoApiCallProps {
apiKey: AppConnectionValueForAuthProperty<typeof foreplayCoAuth>;
method: HttpMethod;
resourceUri: string;
queryParams?: Record<string, string>;
body?: any;
}
export async function foreplayCoApiCall({
apiKey,
method,
resourceUri,
queryParams,
body,
}: ForeplayCoApiCallProps) {
const baseUrl = "https://public.api.foreplay.co";
return httpClient.sendRequest({
method,
url: `${baseUrl}${resourceUri}`,
authentication: {
type: AuthenticationType.BEARER_TOKEN,
token: apiKey.secret_text,
},
queryParams,
body,
});
}

View File

@@ -0,0 +1,585 @@
import { Property } from '@activepieces/pieces-framework';
import { foreplayCoApiCall } from './common';
import { HttpMethod } from '@activepieces/pieces-common';
import { foreplayCoAuth } from '..';
// Common dropdown options (keeping existing functionality)
const orderOptions = () => ({
options: [
{ label: 'Newest', value: 'newest' },
{ label: 'Oldest', value: 'oldest' },
{ label: 'Longest Running', value: 'longest_running' },
{ label: 'Most Relevant', value: 'most_relevant' },
],
});
const liveStatusOptions = () => ({
options: [
{ label: 'Active Only', value: 'true' },
{ label: 'Inactive Only', value: 'false' },
],
});
const displayFormatOptions = () => ({
options: [
{ label: 'Video', value: 'video' },
{ label: 'Carousel', value: 'carousel' },
{ label: 'Image', value: 'image' },
{ label: 'DCO', value: 'dco' },
{ label: 'DPA', value: 'dpa' },
{ label: 'Multi Images', value: 'multi_images' },
{ label: 'Multi Videos', value: 'multi_videos' },
{ label: 'Multi Medias', value: 'multi_medias' },
{ label: 'Event', value: 'event' },
{ label: 'Text', value: 'text' },
],
});
const publisherPlatformOptions = () => ({
options: [
{ label: 'Facebook', value: 'facebook' },
{ label: 'Instagram', value: 'instagram' },
{ label: 'Audience Network', value: 'audience_network' },
{ label: 'Messenger', value: 'messenger' },
{ label: 'TikTok', value: 'tiktok' },
{ label: 'YouTube', value: 'youtube' },
{ label: 'LinkedIn', value: 'linkedin' },
{ label: 'Threads', value: 'threads' },
],
});
const nicheOptions = () => ({
options: [
{ label: 'Accessories', value: 'accessories' },
{ label: 'App/Software', value: 'app/software' },
{ label: 'Beauty', value: 'beauty' },
{ label: 'Business/Professional', value: 'business/professional' },
{ label: 'Education', value: 'education' },
{ label: 'Entertainment', value: 'entertainment' },
{ label: 'Fashion', value: 'fashion' },
{ label: 'Finance', value: 'finance' },
{ label: 'Food', value: 'food' },
{ label: 'Health', value: 'health' },
{ label: 'Home', value: 'home' },
{ label: 'Pets', value: 'pets' },
{ label: 'Sports', value: 'sports' },
{ label: 'Technology', value: 'technology' },
{ label: 'Travel', value: 'travel' },
{ label: 'Automotive', value: 'automotive' },
{ label: 'Other', value: 'other' },
],
});
const marketTargetOptions = () => ({
options: [
{ label: 'B2B (Business-to-Business)', value: 'b2b' },
{ label: 'B2C (Business-to-Consumer)', value: 'b2c' },
],
});
const languageOptions = () => ({
options: [
{ label: 'English', value: 'english' },
{ label: 'French', value: 'french' },
{ label: 'German', value: 'german' },
{ label: 'Italian', value: 'italian' },
{ label: 'Dutch/Flemish', value: 'dutch, flemish' },
{ label: 'Spanish', value: 'spanish' },
{ label: 'Portuguese', value: 'portuguese' },
{ label: 'Romanian', value: 'romanian' },
{ label: 'Russian', value: 'russian' },
{ label: 'Chinese', value: 'chinese' },
{ label: 'Japanese', value: 'japanese' },
{ label: 'Korean', value: 'korean' },
{ label: 'Arabic', value: 'arabic' },
{ label: 'Hindi', value: 'hindi' },
],
});
// Action Properties
export const findAds = () => ({
query: Property.ShortText({
displayName: 'Search Query',
description:
'Search text for ad name or description. Leave empty to search all ads with filters only.',
required: false,
}),
start_date: Property.DateTime({
displayName: 'Start Date',
description:
'Start date (inclusive). Format: YYYY-MM-DD or YYYY-MM-DDTHH:MM:SS',
required: false,
}),
end_date: Property.DateTime({
displayName: 'End Date',
description:
'End date (inclusive). Format: YYYY-MM-DD or YYYY-MM-DDTHH:MM:SS',
required: false,
}),
order: Property.StaticDropdown({
displayName: 'Order',
description:
'Order of results: newest (default), oldest, longest_running, or most_relevant',
required: false,
options: orderOptions(),
}),
live: Property.StaticDropdown({
displayName: 'Live Status',
description:
'Filter ads by live status. true means currently active ads, false means inactive ads.',
required: false,
options: liveStatusOptions(),
}),
display_format: Property.MultiSelectDropdown({
auth: foreplayCoAuth,
displayName: 'Display Format',
description: 'Filter by one or more display formats',
required: false,
refreshers: [],
options: async () => displayFormatOptions(),
}),
publisher_platform: Property.MultiSelectDropdown({
auth: foreplayCoAuth,
displayName: 'Publisher Platform',
description: 'Filter by one or more publisher platforms',
required: false,
refreshers: [],
options: async () => publisherPlatformOptions(),
}),
niches: Property.MultiSelectDropdown({
auth: foreplayCoAuth,
displayName: 'Niches',
description: 'Filter by one or more niches',
required: false,
refreshers: [],
options: async () => nicheOptions(),
}),
market_target: Property.MultiSelectDropdown({
auth: foreplayCoAuth,
displayName: 'Market Target',
description: 'Filter by market target',
required: false,
refreshers: [],
options: async () => marketTargetOptions(),
}),
languages: Property.MultiSelectDropdown({
auth: foreplayCoAuth,
displayName: 'Languages',
description: 'Filter by languages. Accepts various language formats.',
required: false,
refreshers: [],
options: async () => languageOptions(),
}),
cursor: Property.ShortText({
displayName: 'Cursor',
description:
'Cursor for pagination. Use the cursor value from the previous response.',
required: false,
}),
limit: Property.Number({
displayName: 'Limit',
description:
'Pagination limit (default 10, max 250). Controls the number of ads returned per request.',
required: false,
defaultValue: 10,
}),
});
export const getAdById = () => ({
ad_id: Property.ShortText({
displayName: 'Ad ID',
description:
'The unique identifier of the ad (e.g., "ad_1234567890"). You can find this ID from other Foreplay actions or the platform.',
required: true,
}),
});
export const getAdsByPage = () => ({
page_id: Property.ShortText({
displayName: 'Page ID',
description:
'The numeric Facebook page ID (e.g., "123456789"). You can find this in your Facebook page settings or from other Foreplay actions.',
required: true,
}),
start_date: Property.DateTime({
displayName: 'Start Date',
description:
'Start date (inclusive). Format: YYYY-MM-DD or YYYY-MM-DDTHH:MM:SS',
required: false,
}),
end_date: Property.DateTime({
displayName: 'End Date',
description:
'End date (inclusive). Format: YYYY-MM-DD or YYYY-MM-DDTHH:MM:SS',
required: false,
}),
order: Property.StaticDropdown({
displayName: 'Order',
description:
'Order of results: newest (default), oldest, longest_running, or most_relevant',
required: false,
options: orderOptions(),
}),
live: Property.StaticDropdown({
displayName: 'Live Status',
description:
'Filter ads by live status. true means currently active ads, false means inactive ads.',
required: false,
options: liveStatusOptions(),
}),
display_format: Property.MultiSelectDropdown({
auth: foreplayCoAuth,
displayName: 'Display Format',
description: 'Filter by one or more display formats',
required: false,
refreshers: [],
options: async () => displayFormatOptions(),
}),
publisher_platform: Property.MultiSelectDropdown({
auth: foreplayCoAuth,
displayName: 'Publisher Platform',
description: 'Filter by one or more publisher platforms',
required: false,
refreshers: [],
options: async () => publisherPlatformOptions(),
}),
niches: Property.MultiSelectDropdown({
auth: foreplayCoAuth,
displayName: 'Niches',
description: 'Filter by one or more niches',
required: false,
refreshers: [],
options: async () => nicheOptions(),
}),
market_target: Property.MultiSelectDropdown({
auth: foreplayCoAuth,
displayName: 'Market Target',
description: 'Filter by market target',
required: false,
refreshers: [],
options: async () => marketTargetOptions(),
}),
languages: Property.MultiSelectDropdown({
auth: foreplayCoAuth,
displayName: 'Languages',
description: 'Filter by languages. Accepts various language formats.',
required: false,
refreshers: [],
options: async () => languageOptions(),
}),
cursor: Property.ShortText({
displayName: 'Cursor',
description:
'Cursor for pagination. Use the cursor value from the previous response.',
required: false,
}),
limit: Property.Number({
displayName: 'Limit',
description:
'Pagination limit (default 10, max 250). Controls the number of ads returned per request.',
required: false,
defaultValue: 10,
}),
});
export const findBrands = () => ({
query: Property.ShortText({
displayName: 'Brand Name',
description:
'Brand name to search for (e.g., "Nike", "Apple"). Supports fuzzy matching for partial names.',
required: true,
}),
limit: Property.Number({
displayName: 'Limit',
description: 'Number of brands to return (max 10).',
required: false,
defaultValue: 10,
}),
});
export const findBoards = () => ({
offset: Property.Number({
displayName: 'Offset',
description: 'The offset for pagination (default 0).',
required: false,
defaultValue: 0,
}),
limit: Property.Number({
displayName: 'Limit',
description: 'The limit for pagination (default 10, max 10).',
required: false,
defaultValue: 10,
}),
});
// Trigger Properties
export const newAdInBoard = () => ({
board_id: Property.Dropdown({
auth: foreplayCoAuth,
displayName: 'Board',
description: 'Select the board to monitor for new ads.',
required: true,
refreshers: [],
options: async ({ auth }) => {
if (!auth) {
return {
disabled: true,
options: [],
placeholder: 'Please connect your account first',
};
}
try {
const response = await foreplayCoApiCall({
apiKey: auth,
method: HttpMethod.GET,
resourceUri: '/api/boards',
});
const responseBody = response.body;
if (responseBody.metadata && responseBody.metadata.success === true) {
const boards = responseBody.data || [];
return {
options: boards.map((board: any) => ({
label: board.name || board.title || `Board ${board.id}`,
value: board.id,
})),
};
} else {
return {
disabled: true,
options: [],
placeholder: 'Failed to load boards',
};
}
} catch (error) {
return {
disabled: true,
options: [],
placeholder: 'Error loading boards',
};
}
},
}),
polling_interval: Property.Number({
displayName: 'Polling Interval (minutes)',
description: 'How often to check for new ads (in minutes).',
required: false,
defaultValue: 5,
}),
live: Property.StaticDropdown({
displayName: 'Live Status',
description:
'Filter ads by live status. true means currently active ads, false means inactive ads.',
required: false,
options: liveStatusOptions(),
}),
display_format: Property.MultiSelectDropdown({
auth: foreplayCoAuth,
displayName: 'Display Format',
description: 'Filter by one or more display formats',
required: false,
refreshers: [],
options: async () => displayFormatOptions(),
}),
publisher_platform: Property.MultiSelectDropdown({
auth: foreplayCoAuth,
displayName: 'Publisher Platform',
description: 'Filter by one or more publisher platforms',
required: false,
refreshers: [],
options: async () => publisherPlatformOptions(),
}),
niches: Property.MultiSelectDropdown({
auth: foreplayCoAuth,
displayName: 'Niches',
description: 'Filter by one or more niches',
required: false,
refreshers: [],
options: async () => nicheOptions(),
}),
market_target: Property.MultiSelectDropdown({
auth: foreplayCoAuth,
displayName: 'Market Target',
description: 'Filter by market target',
required: false,
refreshers: [],
options: async () => marketTargetOptions(),
}),
languages: Property.MultiSelectDropdown({
auth: foreplayCoAuth,
displayName: 'Languages',
description: 'Filter by languages. Accepts various language formats.',
required: false,
refreshers: [],
options: async () => languageOptions(),
}),
});
export const newAdInSpyder = () => ({
brand_id: Property.Dropdown({
auth: foreplayCoAuth,
displayName: 'Brand',
description: 'Select the brand to monitor for new ads.',
required: true,
refreshers: [],
options: async ({ auth }) => {
if (!auth) {
return {
disabled: true,
options: [],
placeholder: 'Please connect your account first',
};
}
try {
const response = await foreplayCoApiCall({
apiKey: auth,
method: HttpMethod.GET,
resourceUri: '/api/spyder/brands',
});
const responseBody = response.body;
if (responseBody.metadata && responseBody.metadata.success === true) {
const brands = responseBody.data || [];
return {
options: brands.map((brand: any) => ({
label: brand.name || brand.id,
value: brand.id,
})),
};
} else {
return {
disabled: true,
options: [],
placeholder: 'Failed to load brands',
};
}
} catch (error) {
return {
disabled: true,
options: [],
placeholder: 'Error loading brands',
};
}
},
}),
polling_interval: Property.Number({
displayName: 'Polling Interval (minutes)',
description: 'How often to check for new ads (in minutes).',
required: false,
defaultValue: 5,
}),
live: Property.StaticDropdown({
displayName: 'Live Status',
description:
'Filter ads by live status. true means currently active ads, false means inactive ads.',
required: false,
options: liveStatusOptions(),
}),
display_format: Property.MultiSelectDropdown({
auth: foreplayCoAuth,
displayName: 'Display Format',
description: 'Filter by one or more display formats',
required: false,
refreshers: [],
options: async () => displayFormatOptions(),
}),
publisher_platform: Property.MultiSelectDropdown({
auth: foreplayCoAuth,
displayName: 'Publisher Platform',
description: 'Filter by one or more publisher platforms',
required: false,
refreshers: [],
options: async () => publisherPlatformOptions(),
}),
niches: Property.MultiSelectDropdown({
auth: foreplayCoAuth,
displayName: 'Niches',
description: 'Filter by one or more niches',
required: false,
refreshers: [],
options: async () => nicheOptions(),
}),
market_target: Property.MultiSelectDropdown({
auth: foreplayCoAuth,
displayName: 'Market Target',
description: 'Filter by market target',
required: false,
refreshers: [],
options: async () => marketTargetOptions(),
}),
languages: Property.MultiSelectDropdown({
auth: foreplayCoAuth,
displayName: 'Languages',
description: 'Filter by languages. Accepts various language formats.',
required: false,
refreshers: [],
options: async () => languageOptions(),
}),
});
export const newSwipefileAd = () => ({
polling_interval: Property.Number({
displayName: 'Polling Interval (minutes)',
description: 'How often to check for new ads (in minutes).',
required: false,
defaultValue: 5,
}),
start_date: Property.DateTime({
displayName: 'Start Date',
description: 'Filter ads published after this date.',
required: false,
}),
end_date: Property.DateTime({
displayName: 'End Date',
description: 'Filter ads published before this date.',
required: false,
}),
live: Property.StaticDropdown({
displayName: 'Live Status',
description: 'Filter by ad status (active/inactive).',
required: false,
options: liveStatusOptions(),
}),
display_format: Property.MultiSelectDropdown({
auth: foreplayCoAuth,
displayName: 'Display Format',
description: 'Filter by ad format (video, image, carousel, etc.).',
required: false,
refreshers: [],
options: async () => displayFormatOptions(),
}),
publisher_platform: Property.MultiSelectDropdown({
auth: foreplayCoAuth,
displayName: 'Publisher Platform',
description: 'Filter by platform (Facebook, Instagram, etc.).',
required: false,
refreshers: [],
options: async () => publisherPlatformOptions(),
}),
niches: Property.MultiSelectDropdown({
auth: foreplayCoAuth,
displayName: 'Niches',
description: 'Filter by industry/category.',
required: false,
refreshers: [],
options: async () => nicheOptions(),
}),
market_target: Property.MultiSelectDropdown({
auth: foreplayCoAuth,
displayName: 'Market Target',
description: 'Filter by target audience (B2B, B2C).',
required: false,
refreshers: [],
options: async () => marketTargetOptions(),
}),
languages: Property.MultiSelectDropdown({
auth: foreplayCoAuth,
displayName: 'Languages',
description: 'Filter by ad language.',
required: false,
refreshers: [],
options: async () => languageOptions(),
}),
});

View File

@@ -0,0 +1,149 @@
import z from 'zod';
// Common validation schemas for dropdown options
const orderOptions = z.enum([
'newest',
'oldest',
'longest_running',
'most_relevant',
]);
const liveStatusOptions = z.enum(['true', 'false']);
const displayFormatOptions = z.enum([
'video',
'carousel',
'image',
'dco',
'dpa',
'multi_images',
'multi_videos',
'multi_medias',
'event',
'text',
]);
const publisherPlatformOptions = z.enum([
'facebook',
'instagram',
'audience_network',
'messenger',
'tiktok',
'youtube',
'linkedin',
'threads',
]);
const nicheOptions = z.enum([
'accessories',
'app/software',
'beauty',
'business/professional',
'education',
'entertainment',
'fashion',
'finance',
'food',
'health',
'home',
'pets',
'sports',
'technology',
'travel',
'automotive',
'other',
]);
const marketTargetOptions = z.enum(['b2b', 'b2c']);
const languageOptions = z.enum([
'english',
'french',
'german',
'italian',
'dutch, flemish',
'spanish',
'portuguese',
'romanian',
'russian',
'chinese',
'japanese',
'korean',
'arabic',
'hindi',
]);
const brandOrderOptions = z.enum(['most_ranked', 'least_ranked']);
// Action Schemas (Zod objects for validation)
export const findAdsSchema = z.object({
query: z.string().optional(),
start_date: z.string().optional(),
end_date: z.string().optional(),
order: orderOptions.optional(),
live: liveStatusOptions.optional(),
display_format: z.array(displayFormatOptions).optional(),
publisher_platform: z.array(publisherPlatformOptions).optional(),
niches: z.array(nicheOptions).optional(),
market_target: z.array(marketTargetOptions).optional(),
languages: z.array(languageOptions).optional(),
cursor: z.string().optional(),
limit: z.number().min(1).max(250).optional(),
});
export const getAdByIdSchema = z.object({
ad_id: z.string().min(1, 'Ad ID is required'),
});
export const getAdsByPageSchema = z.object({
page_id: z.string().min(1, 'Page ID is required'),
start_date: z.string().optional(),
end_date: z.string().optional(),
order: orderOptions.optional(),
live: liveStatusOptions.optional(),
display_format: z.array(displayFormatOptions).optional(),
publisher_platform: z.array(publisherPlatformOptions).optional(),
niches: z.array(nicheOptions).optional(),
market_target: z.array(marketTargetOptions).optional(),
languages: z.array(languageOptions).optional(),
cursor: z.string().optional(),
limit: z.number().min(1).max(250).optional(),
});
export const findBrandsSchema = z.object({
query: z.string().min(1, 'Brand name is required'),
limit: z.number().min(1).max(10).optional(),
});
export const findBoardsSchema = z.object({
offset: z.number().min(0).optional(),
limit: z.number().min(1).max(10).optional(),
});
// Trigger Schemas
export const newAdInBoardSchema = z.object({
board_id: z.string().min(1, 'Board ID is required'),
polling_interval: z.number().min(1).max(1440).optional(),
live: liveStatusOptions.optional(),
display_format: z.array(displayFormatOptions).optional(),
publisher_platform: z.array(publisherPlatformOptions).optional(),
niches: z.array(nicheOptions).optional(),
market_target: z.array(marketTargetOptions).optional(),
languages: z.array(languageOptions).optional(),
});
export const newAdInSpyderSchema = z.object({
brand_id: z.string().min(1, 'Brand ID is required'),
polling_interval: z.number().min(1).max(1440).optional(),
live: liveStatusOptions.optional(),
display_format: z.array(displayFormatOptions).optional(),
publisher_platform: z.array(publisherPlatformOptions).optional(),
niches: z.array(nicheOptions).optional(),
market_target: z.array(marketTargetOptions).optional(),
languages: z.array(languageOptions).optional(),
});
export const newSwipefileAdSchema = z.object({
polling_interval: z.number().min(1).max(1440).optional(),
start_date: z.string().optional(),
end_date: z.string().optional(),
live: liveStatusOptions.optional(),
display_format: z.array(displayFormatOptions).optional(),
publisher_platform: z.array(publisherPlatformOptions).optional(),
niches: z.array(nicheOptions).optional(),
market_target: z.array(marketTargetOptions).optional(),
languages: z.array(languageOptions).optional(),
});

View File

@@ -0,0 +1,3 @@
export { newAdInSpyder } from './new-ad-in-spyder';
export { newAdInBoard } from './new-ad-in-board';
export { newSwipefileAd } from './new-swipefile-ad';

View File

@@ -0,0 +1,178 @@
import { createTrigger, TriggerStrategy, Property, AppConnectionValueForAuthProperty } from "@activepieces/pieces-framework";
import { foreplayCoApiCall } from "../common";
import { HttpMethod, Polling, DedupeStrategy, pollingHelper } from "@activepieces/pieces-common";
import { newAdInBoard as newAdInBoardProperties } from "../properties";
import { newAdInBoardSchema } from "../schemas";
import { foreplayCoAuth } from "../..";
const getBoardsDropdown = async (auth: AppConnectionValueForAuthProperty<typeof foreplayCoAuth>) => {
try {
const response = await foreplayCoApiCall({
apiKey: auth,
method: HttpMethod.GET,
resourceUri: '/api/boards',
});
const responseBody = response.body;
if (responseBody.metadata && responseBody.metadata.success === true && responseBody.data) {
return {
options: responseBody.data.map((board: any) => ({
label: board.name || board.title || `Board ${board.id}`,
value: board.id
}))
};
}
return { options: [] };
} catch (error) {
console.error('Error fetching boards for dropdown:', error);
return { options: [] };
}
};
const polling: Polling<AppConnectionValueForAuthProperty<typeof foreplayCoAuth>, Record<string, any>> = {
strategy: DedupeStrategy.TIMEBASED,
items: async ({ auth, propsValue, lastFetchEpochMS }) => {
const { board_id } = propsValue;
console.log(`[New Ad in Board Polling] Fetching ads for board: ${board_id}, lastFetch: ${new Date(lastFetchEpochMS || 0).toISOString()}`);
const queryParams: Record<string, string> = {
board_id: board_id,
limit: String(250), // Max limit to get more ads
order: 'newest'
};
// Add optional filters if provided
if (propsValue['live'] !== undefined) {
queryParams['live'] = String(propsValue['live'] === 'true');
}
if (propsValue['display_format'] && propsValue['display_format'].length > 0) {
(queryParams as any).display_format = propsValue['display_format'];
}
if (propsValue['publisher_platform'] && propsValue['publisher_platform'].length > 0) {
(queryParams as any).publisher_platform = propsValue['publisher_platform'];
}
if (propsValue['niches'] && propsValue['niches'].length > 0) {
(queryParams as any).niches = propsValue['niches'];
}
if (propsValue['market_target'] && propsValue['market_target'].length > 0) {
(queryParams as any).market_target = propsValue['market_target'];
}
if (propsValue['languages'] && propsValue['languages'].length > 0) {
(queryParams as any).languages = propsValue['languages'];
}
const response = await foreplayCoApiCall({
apiKey: auth,
method: HttpMethod.GET,
resourceUri: '/api/board/ads',
queryParams,
});
const responseBody = response.body;
if (!responseBody.metadata || !responseBody.metadata.success) {
console.log(`[New Ad in Board Polling] API call failed:`, responseBody);
return [];
}
const ads = responseBody.data || [];
console.log(`[New Ad in Board Polling] Found ${ads.length} ads for board ${board_id}`);
return ads.map((ad: any) => ({
epochMilliSeconds: new Date(ad.created_at).getTime(),
data: ad,
}));
}
};
export const newAdInBoard = createTrigger({
name: 'newAdInBoard',
displayName: 'New Ad in Board',
auth: foreplayCoAuth,
description: 'Triggers when a new ad is added to the selected board.',
type: TriggerStrategy.POLLING,
sampleData: {
id: "ad_789",
board_id: "board_456",
brand_id: "brand_456",
title: "New Campaign Ad",
description: "Latest marketing campaign",
live: true,
display_format: "video",
publisher_platform: ["facebook"],
niches: ["fashion"],
market_target: "b2c",
languages: ["en"],
created_at: "2024-01-15T10:30:00Z",
updated_at: "2024-01-15T10:30:00Z"
},
props: newAdInBoardProperties(),
async test(context) {
// Validate props using Zod schema
const validation = newAdInBoardSchema.safeParse(context.propsValue);
if (!validation.success) {
throw new Error(`Validation failed: ${validation.error.message}`);
}
return await pollingHelper.test(polling, {
auth: context.auth,
store: context.store,
propsValue: context.propsValue,
files: context.files,
});
},
async onEnable(context) {
await pollingHelper.onEnable(polling, {
auth: context.auth,
store: context.store,
propsValue: context.propsValue,
});
},
async onDisable(context) {
await pollingHelper.onDisable(polling, {
store: context.store,
propsValue: context.propsValue,
auth: context.auth,
});
},
async run(context) {
// Validate props using Zod schema
const validation = newAdInBoardSchema.safeParse(context.propsValue);
if (!validation.success) {
throw new Error(`Validation failed: ${validation.error.message}`);
}
const result = await pollingHelper.poll(polling, {
auth: context.auth,
store: context.store,
propsValue: context.propsValue,
files: context.files,
});
// Transform the result to match our expected format
return result.map((item: any) => ({
id: item.data.id,
board_id: context.propsValue.board_id,
brand_id: item.data.brand_id,
title: item.data.title || item.data.name,
description: item.data.description,
live: item.data.live,
display_format: item.data.display_format,
publisher_platform: item.data.publisher_platform,
niches: item.data.niches,
market_target: item.data.market_target,
languages: item.data.languages,
created_at: item.data.created_at,
updated_at: item.data.updated_at,
metadata: { success: true, message: 'New ad detected' }
}));
}
});

View File

@@ -0,0 +1,154 @@
import { AppConnectionValueForAuthProperty, createTrigger, TriggerStrategy } from '@activepieces/pieces-framework';
import { foreplayCoApiCall } from '../common';
import {
HttpMethod,
Polling,
DedupeStrategy,
pollingHelper,
} from '@activepieces/pieces-common';
import { newAdInSpyder as newAdInSpyderProperties } from '../properties';
import { newAdInSpyderSchema } from '../schemas';
import { foreplayCoAuth } from '../..';
const polling: Polling<AppConnectionValueForAuthProperty<typeof foreplayCoAuth>, Record<string, any>> = {
strategy: DedupeStrategy.TIMEBASED,
items: async ({ auth, propsValue }) => {
const { brand_id } = propsValue;
// Build query parameters with user's filter preferences
const queryParams = new URLSearchParams();
queryParams.append('brand_id', brand_id);
queryParams.append('limit', String(50)); // Reasonable default for polling
queryParams.append('order', 'newest');
// Add optional filters if provided
if (propsValue['live']) {
queryParams.append('live', String(propsValue['live']));
}
if (
propsValue['display_format'] &&
propsValue['display_format'].length > 0
) {
propsValue['display_format'].forEach((format: unknown) => {
queryParams.append('display_format', String(format));
});
}
if (
propsValue['publisher_platform'] &&
propsValue['publisher_platform'].length > 0
) {
propsValue['publisher_platform'].forEach((platform: unknown) => {
queryParams.append('publisher_platform', String(platform));
});
}
if (propsValue['niches'] && propsValue['niches'].length > 0) {
propsValue['niches'].forEach((niche: unknown) => {
queryParams.append('niches', String(niche));
});
}
if (propsValue['market_target'] && propsValue['market_target'].length > 0) {
propsValue['market_target'].forEach((target: unknown) => {
queryParams.append('market_target', String(target));
});
}
if (propsValue['languages'] && propsValue['languages'].length > 0) {
propsValue['languages'].forEach((language: unknown) => {
queryParams.append('languages', String(language));
});
}
const queryString = queryParams.toString();
const fullUrl = `/api/spyder/brand/ads?${queryString}`;
const response = await foreplayCoApiCall({
apiKey: auth,
method: HttpMethod.GET,
resourceUri: fullUrl,
});
const responseBody = response.body;
if (!responseBody.metadata || !responseBody.metadata.success) {
return [];
}
const ads = responseBody.data || [];
return ads.map((ad: any) => ({
epochMilliSeconds: new Date(ad.created_at).getTime(),
data: ad,
}));
},
};
export const newAdInSpyder = createTrigger({
name: 'newAdInSpyder',
displayName: 'New Ad in Spyder',
description: 'Triggers when new ads are added for a brand in Spyder.',
type: TriggerStrategy.POLLING,
sampleData: {
id: 'ad_123456789',
brand_id: 'brand_987654321',
title: 'New Summer Sale Ad',
description: 'A great summer sale ad.',
live: true,
display_format: 'video',
publisher_platform: ['facebook'],
niches: ['fashion'],
market_target: 'b2c',
languages: ['en'],
created_at: '2024-01-15T10:30:00Z',
updated_at: '2024-01-15T10:30:00Z',
},
props: newAdInSpyderProperties(),
auth: foreplayCoAuth,
async test(context) {
// Validate props using Zod schema
const validation = newAdInSpyderSchema.safeParse(context.propsValue);
if (!validation.success) {
throw new Error(`Validation failed: ${validation.error.message}`);
}
return await pollingHelper.test(polling, {
auth: context.auth,
store: context.store,
propsValue: context.propsValue,
files: context.files,
});
},
async onEnable(context) {
await pollingHelper.onEnable(polling, {
auth: context.auth,
store: context.store,
propsValue: context.propsValue,
});
},
async onDisable(context) {
await pollingHelper.onDisable(polling, {
store: context.store,
propsValue: context.propsValue,
auth: context.auth,
});
},
async run(context) {
// Validate props using Zod schema
const validation = newAdInSpyderSchema.safeParse(context.propsValue);
if (!validation.success) {
throw new Error(`Validation failed: ${validation.error.message}`);
}
const result = await pollingHelper.poll(polling, {
auth: context.auth,
store: context.store,
propsValue: context.propsValue,
files: context.files,
});
// Return clean ad data for automation workflows
return result.map((item: any) => item.data);
},
});

View File

@@ -0,0 +1,163 @@
import { createTrigger, TriggerStrategy, Property, AppConnectionValueForAuthProperty } from "@activepieces/pieces-framework";
import { foreplayCoApiCall } from "../common";
import { HttpMethod, Polling, DedupeStrategy, pollingHelper } from "@activepieces/pieces-common";
import { newSwipefileAd as newSwipefileAdProperties } from "../properties";
import { newSwipefileAdSchema } from "../schemas";
import { foreplayCoAuth } from "../..";
const polling: Polling<AppConnectionValueForAuthProperty<typeof foreplayCoAuth>, Record<string, any>> = {
strategy: DedupeStrategy.TIMEBASED,
items: async ({ auth, propsValue, lastFetchEpochMS }) => {
console.log(`[New Swipefile Ad Polling] Fetching swipefile ads, lastFetch: ${new Date(lastFetchEpochMS || 0).toISOString()}`);
const queryParams: Record<string, string> = {
limit: String(250), // Max limit to get more ads
order: 'newest'
};
// Add optional filters if provided
if (propsValue['start_date']) {
queryParams['start_date'] = propsValue['start_date'];
}
if (propsValue['end_date']) {
queryParams['end_date'] = propsValue['end_date'];
}
if (propsValue['live'] !== undefined) {
queryParams['live'] = String(propsValue['live'] === 'true');
}
if (propsValue['display_format'] && propsValue['display_format'].length > 0) {
(queryParams as any).display_format = propsValue['display_format'];
}
if (propsValue['publisher_platform'] && propsValue['publisher_platform'].length > 0) {
(queryParams as any).publisher_platform = propsValue['publisher_platform'];
}
if (propsValue['niches'] && propsValue['niches'].length > 0) {
(queryParams as any).niches = propsValue['niches'];
}
if (propsValue['market_target'] && propsValue['market_target'].length > 0) {
(queryParams as any).market_target = propsValue['market_target'];
}
if (propsValue['languages'] && propsValue['languages'].length > 0) {
(queryParams as any).languages = propsValue['languages'];
}
const response = await foreplayCoApiCall({
apiKey: auth,
method: HttpMethod.GET,
resourceUri: '/api/swipefile/ads',
queryParams,
});
const responseBody = response.body;
if (!responseBody.metadata || !responseBody.metadata.success) {
console.log(`[New Swipefile Ad Polling] API call failed:`, responseBody);
return [];
}
const ads = responseBody.data || [];
console.log(`[New Swipefile Ad Polling] Found ${ads.length} swipefile ads`);
return ads.map((ad: any) => ({
epochMilliSeconds: new Date(ad.created_at).getTime(),
data: ad,
}));
}
};
export const newSwipefileAd = createTrigger({
name: 'newSwipefileAd',
displayName: 'New Swipefile Ad',
description: 'Triggers when a new ad is added to your swipefile collection.',
type: TriggerStrategy.POLLING,
sampleData: {
id: "ad_123456789",
brand_id: "brand_987654321",
brand_name: "Nike",
title: "Just Do It - New Collection",
description: "Discover our latest athletic wear collection",
live: true,
display_format: "video",
publisher_platform: ["facebook"],
niches: ["sports", "fashion"],
market_target: "b2c",
languages: ["en"],
created_at: "2024-01-15T10:30:00Z",
updated_at: "2024-01-15T10:30:00Z",
media_urls: [
"https://example.com/video1.mp4",
"https://example.com/image1.jpg"
],
ad_library_id: "123456789",
ad_library_url: "https://www.facebook.com/ads/library/?active_status=all&ad_type=all&country=US&view_all_page_id=123456789"
},
props: newSwipefileAdProperties(),
auth: foreplayCoAuth,
async test(context) {
// Validate props using Zod schema
const validation = newSwipefileAdSchema.safeParse(context.propsValue);
if (!validation.success) {
throw new Error(`Validation failed: ${validation.error.message}`);
}
return await pollingHelper.test(polling, {
auth: context.auth,
store: context.store,
propsValue: context.propsValue,
files: context.files,
});
},
async onEnable(context) {
await pollingHelper.onEnable(polling, {
auth: context.auth,
store: context.store,
propsValue: context.propsValue,
});
},
async onDisable(context) {
await pollingHelper.onDisable(polling, {
store: context.store,
propsValue: context.propsValue,
auth: context.auth,
});
},
async run(context) {
// Validate props using Zod schema
const validation = newSwipefileAdSchema.safeParse(context.propsValue);
if (!validation.success) {
throw new Error(`Validation failed: ${validation.error.message}`);
}
const result = await pollingHelper.poll(polling, {
auth: context.auth,
store: context.store,
propsValue: context.propsValue,
files: context.files,
});
// Transform the result to match our expected format
return result.map((item: any) => ({
id: item.data.id,
brand_id: item.data.brand_id,
brand_name: item.data.brand_name,
title: item.data.title,
description: item.data.description,
live: item.data.live,
display_format: item.data.display_format,
publisher_platform: item.data.publisher_platform,
niches: item.data.niches,
market_target: item.data.market_target,
languages: item.data.languages,
created_at: item.data.created_at,
updated_at: item.data.updated_at,
media_urls: item.data.media_urls,
ad_library_id: item.data.ad_library_id,
ad_library_url: item.data.ad_library_url,
metadata: { success: true, message: 'New ad detected' }
}));
}
});

View File

@@ -0,0 +1,20 @@
{
"extends": "../../../../tsconfig.base.json",
"compilerOptions": {
"module": "commonjs",
"forceConsistentCasingInFileNames": true,
"strict": true,
"importHelpers": true,
"noImplicitOverride": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"noPropertyAccessFromIndexSignature": true
},
"files": [],
"include": [],
"references": [
{
"path": "./tsconfig.lib.json"
}
]
}

View File

@@ -0,0 +1,9 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../../../dist/out-tsc",
"declaration": true,
"types": ["node"]
},
"include": ["src/**/*.ts"]
}