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-pinterest
This library was generated with [Nx](https://nx.dev).
## Building
Run `nx build pieces-pinterest` to build the library.

View File

@@ -0,0 +1,4 @@
{
"name": "@activepieces/piece-pinterest",
"version": "0.0.2"
}

View File

@@ -0,0 +1,65 @@
{
"name": "pieces-pinterest",
"$schema": "../../../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "packages/pieces/community/pinterest/src",
"projectType": "library",
"release": {
"version": {
"currentVersionResolver": "git-tag",
"preserveLocalDependencyProtocols": false,
"manifestRootsToUpdate": [
"dist/{projectRoot}"
]
}
},
"tags": [],
"targets": {
"build": {
"executor": "@nx/js:tsc",
"outputs": [
"{options.outputPath}"
],
"options": {
"outputPath": "dist/packages/pieces/community/pinterest",
"tsConfig": "packages/pieces/community/pinterest/tsconfig.lib.json",
"packageJson": "packages/pieces/community/pinterest/package.json",
"main": "packages/pieces/community/pinterest/src/index.ts",
"assets": [
"packages/pieces/community/pinterest/*.md",
{
"input": "packages/pieces/community/pinterest/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/pinterest",
"command": "bun install --no-save --silent"
},
"dependsOn": [
"^build"
]
}
}
}

View File

@@ -0,0 +1,90 @@
{
"Connect your Pinterest Business Account": "Verbinden Sie Ihr Pinterest Business Konto",
"Create Pin": "Pin erstellen",
"Create Board": "Board erstellen",
"Delete Pin": "Pin löschen",
"Find Board by Name": "Brett nach Namen suchen",
"Find Pin by Title/Keyword": "Pin nach Titel/Stichwort finden",
"Update Board": "Board aktualisieren",
"Upload an image or video to create a new Pin on a board.": "Ein Bild oder Video hochladen, um einen neuen Pin auf einem Board zu erstellen.",
"Create a new Pinterest board for organizing Pins.": "Erstellen Sie ein neues Pinterest Board für die Organisation von Pins.",
"Permanently delete a specific Pin.": "Einen bestimmten Pin dauerhaft löschen.",
"Search for boards by name using Pinterest's search API.": "Suchen Sie nach Boards mit der Suche API von Pinterest nach Namen.",
"Search for Pins using title, description, or keywords.": "Suche nach Pins mit Titel, Beschreibung oder Schlüsselwörtern.",
"Update a board's name, description, or privacy settings.": "Name, Beschreibung oder Privatsphäre-Einstellungen eines Boards aktualisieren.",
"Ad account Id": "Anzeigen-Konto-Id",
"Board Id": "Board-Id",
"Board Section Id": "Board-Sektion-Id",
"Title": "Titel",
"Description": "Beschreibung",
"Media Source Type": "Medienquellentyp",
"Media URL": "Medien-URL",
"Destination Link": "Ziellink",
"Dominant Color": "Dominante Farbe",
"Alt Text": "Alt Text",
"Parent Pin ID": "Übergeordnete Pin-ID",
"Sponsor ID": "Sponsor ID",
"Product Tags": "Produkt-Tags",
"Note": "Notiz",
"Is Removable": "Ist abnehmbar",
"Board Name": "Boardname",
"Privacy": "Privatsphäre",
"Ads Only Board": "Nur Werbung Board",
"pin Id": "pin Id",
"Search Query": "Suchanfrage",
"Bookmark": "Lesezeichen",
"Pagination Bookmark": "Seiten-Lesezeichen",
"Maximum Results": "Maximale Ergebnisse",
"The title of the Pin (max 100 characters).": "Der Titel des Pin (max. 100 Zeichen).",
"The description of the Pin (max 800 characters).": "Die Beschreibung des Pin (max. 800 Zeichen).",
"The type of media source for the Pin.": "Der Typ der Medienquelle für den Pin.",
"The URL of the image or video to upload. Must be a valid URL.": "Die URL des Bildes oder Videos zum Hochladen. Muss eine gültige URL sein.",
"The destination URL that the Pin will link to when clicked.": "Die Ziel-URL, auf die der Pin verlinkt, wenn angeklickt.",
"The dominant color of the Pin as a hex color code (e.g., \"#6E7874\").": "Die dominante Farbe des Pins als Hex-Farbcode (z.B. \"#6E7874\").",
"Alternative text for accessibility and screen readers (max 500 characters).": "Alternativer Text für Barrierefreiheit und Screenreader (max. 500 Zeichen).",
"The ID of the original Pin if this is a saved/repinned Pin.": "Die ID des ursprünglichen Pins wenn es sich um einen gespeicherten/reparierten Pin handelt.",
"The sponsor account ID for paid partnership content. Available only to select users in closed beta.": "Die Sponsor Konto-ID für kostenpflichtige Partnerschaften. Verfügbar nur um Benutzer in der geschlossenen Beta auszuwählen.",
"Select one or more options": "Wählen Sie eine oder mehrere Optionen",
"A private note for this Pin that only you can see.": "Eine private Notiz für diesen Pin, die nur Sie sehen können.",
"Set to true to create an ad-only Pin that can be easily removed.": "Auf true setzen um einen ad-only Pin zu erstellen, der leicht entfernt werden kann.",
"The name of the board (max 180 characters).": "Der Name des Boards (max. 180 Zeichen).",
"Optional description for your board.": "Optionale Beschreibung für Ihr Board.",
"Board privacy setting (auto-set to \"PROTECTED\" for ad-only boards).": "Board-Privatsphäre-Einstellung (automatisch auf \"PROTECTED\" für Nur-Werbung-Boards gesetzt).",
"Create an ad-only board that can only store promotional Pins. Note: Board name will become \"Ad-only Pins\" and privacy will be set to \"PROTECTED\".": "Erstellen Sie ein Werbe-Board, das nur Werbe-Pins speichern kann. Hinweis: Der Board-Name wird zu \"Werbe-Nur-Pins\" und die Privatsphäre wird auf \"PROTECTED\" gesetzt.",
"The search term to find boards (required).": "Der Suchbegriff zu finden Boards (erforderlich).",
"Pagination bookmark from previous response.": "Lesezeichen für Paginierung von vorheriger Antwort.",
"Search terms for pin titles, descriptions, or tags. You can also search using comma-separated pin IDs.": "Suchbegriffe für Pin-Titel, Beschreibungen oder Tags. Sie können auch mit Komma-getrennten Pin-IDs suchen.",
"Bookmark token from previous search results for pagination.": "Lesezeichen-Token von vorherigen Suchergebnissen für die Seiteninierung.",
"Maximum number of pins to return (useful for large result sets).": "Maximale Anzahl an Pins die zurückgegeben werden (nützlich für große Ergebnisse).",
"The new name of the board (max 180 characters). Leave empty to keep current name.": "Der neue Name des Boards (max. 180 Zeichen). Leer lassen, um den aktuellen Namen zu behalten.",
"The new description of the board (max 500 characters). Leave empty to keep current description.": "Die neue Beschreibung des Boards (max. 500 Zeichen). Leer lassen, um die aktuelle Beschreibung zu behalten.",
"Update board privacy setting. Leave empty to keep current setting.": "Datenschutzeinstellungen des Boards aktualisieren. Leer lassen, um die aktuelle Einstellung zu behalten.",
"Image URL": "Bild-URL",
"Base64 Image": "Base64-Bild",
"Video URL": "Video-URL",
"Public": "Öffentlich",
"Protected": "Geschützt",
"Secret": "Geheimnis",
"New Board": "Neues Board",
"New Follower": "Neuer Follower",
"New Pin on Board": "Neuer Pin auf dem Board",
"Fires when a new board is created in the account.": "Feuert ab, wenn ein neues Board im Konto erstellt wird.",
"Triggers when a user gains a new follower.": "Wird ausgelöst, wenn ein Benutzer einen neuen Follower erhält.",
"Fires when a new Pin is added to a specific board.": "Feuert ab, wenn ein neuer Pin einem bestimmten Board hinzugefügt wird.",
"Board Privacy Filter": "Datenschutz-Filter",
"Page Size": "Einträge pro Seite",
"Pin Types to Watch": "Zu beobachtende Typen anheften",
"Filter boards by privacy setting (optional).": "Foren nach Datenschutzeinstellungen filtern (optional).",
"Number of boards to fetch per page (1-250, default: 25).": "Anzahl der Boards pro Seite (1-250, Standard: 25).",
"Filter by specific pin types. Leave empty to watch all types.": "Nach bestimmten Pin-Typen filtern. Leer lassen, um alle Typen zu beobachten.",
"All Boards": "Alle Boards",
"Public Only": "Nur öffentlich",
"Protected Only": "Nur Geschützt",
"Secret Only": "Nur Geheimnis",
"Public and Secret": "Öffentliche und geheime",
"Regular Pins": "Normale Pins",
"Video Pins": "Video-Pins",
"Shopping Pins": "Einkaufsstifte",
"Carousel Pins": "Carousel Pins",
"Idea Pins": "Ideenstifte"
}

View File

@@ -0,0 +1,90 @@
{
"Connect your Pinterest Business Account": "Conecte su cuenta de Pinterest Business",
"Create Pin": "Crear pin",
"Create Board": "Crear tablero",
"Delete Pin": "Eliminar pin",
"Find Board by Name": "Buscar foro por nombre",
"Find Pin by Title/Keyword": "Buscar alfileres por título/palabra clave",
"Update Board": "Actualizar Tablero",
"Upload an image or video to create a new Pin on a board.": "Sube una imagen o vídeo para crear un nuevo Pin en un foro.",
"Create a new Pinterest board for organizing Pins.": "Crear un nuevo tablero de Pinterest para organizar Pins.",
"Permanently delete a specific Pin.": "Elimina permanentemente un pin específico.",
"Search for boards by name using Pinterest's search API.": "Buscar tableros por nombre usando la API de búsqueda de Pinterest.",
"Search for Pins using title, description, or keywords.": "Buscar Pines usando título, descripción o palabras clave.",
"Update a board's name, description, or privacy settings.": "Actualizar el nombre, la descripción o la configuración de privacidad de un tablero.",
"Ad account Id": "Id de cuenta de anuncio",
"Board Id": "Tablero Id",
"Board Section Id": "Id de la sección del foro",
"Title": "Título",
"Description": "Descripción",
"Media Source Type": "Tipo de fuente Multimedia",
"Media URL": "URL de medios",
"Destination Link": "Enlace de destino",
"Dominant Color": "Color dominante",
"Alt Text": "Texto Alt",
"Parent Pin ID": "Pin ID padre",
"Sponsor ID": "ID del patrocinador",
"Product Tags": "Etiquetas de producto",
"Note": "Nota",
"Is Removable": "Es eliminable",
"Board Name": "Nombre del foro",
"Privacy": "Privacidad",
"Ads Only Board": "Solo tablero de anuncios",
"pin Id": "pin Id",
"Search Query": "Buscar consulta",
"Bookmark": "Marcador",
"Pagination Bookmark": "Marcador de paginación",
"Maximum Results": "Resultados máximos",
"The title of the Pin (max 100 characters).": "El título del Pin (máximo 100 caracteres).",
"The description of the Pin (max 800 characters).": "La descripción del Pin (máximo 800 caracteres).",
"The type of media source for the Pin.": "El tipo de fuente de medios para el Pin.",
"The URL of the image or video to upload. Must be a valid URL.": "La URL de la imagen o vídeo a cargar. Debe ser una URL válida.",
"The destination URL that the Pin will link to when clicked.": "La URL de destino a la que el Pin enlazará cuando se haga clic.",
"The dominant color of the Pin as a hex color code (e.g., \"#6E7874\").": "El color dominante del Pin como código hexadecimal de color (por ejemplo, \"#6E7874\").",
"Alternative text for accessibility and screen readers (max 500 characters).": "Texto alternativo para accesibilidad y lectores de pantalla (máximo 500 caracteres).",
"The ID of the original Pin if this is a saved/repinned Pin.": "El ID del Pin original si es un Pin guardado/repinnado.",
"The sponsor account ID for paid partnership content. Available only to select users in closed beta.": "El ID de la cuenta de patrocinador para el contenido de la asociación pagada. Disponible sólo para seleccionar usuarios en beta cerrada.",
"Select one or more options": "Seleccione una o más opciones",
"A private note for this Pin that only you can see.": "Una nota privada para este Pin que sólo usted puede ver.",
"Set to true to create an ad-only Pin that can be easily removed.": "Establecer en true para crear un pin de sólo anuncios que se puede eliminar fácilmente.",
"The name of the board (max 180 characters).": "El nombre del tablero (máximo 180 caracteres).",
"Optional description for your board.": "Descripción opcional para tu foro.",
"Board privacy setting (auto-set to \"PROTECTED\" for ad-only boards).": "Configuración de privacidad del foro (auto-set a \"PROTECTED\" para tableros de sólo anuncios).",
"Create an ad-only board that can only store promotional Pins. Note: Board name will become \"Ad-only Pins\" and privacy will be set to \"PROTECTED\".": "Crear un tablero de sólo publicidad que sólo puede almacenar alfileres promocionales. Nota: El nombre del tablero se convertirá en \"Pines de sólo anuncios\" y la privacidad se establecerá en \"PROTECTED\".",
"The search term to find boards (required).": "El término de búsqueda para encontrar foros (requerido).",
"Pagination bookmark from previous response.": "Marcador de paginación de la respuesta anterior.",
"Search terms for pin titles, descriptions, or tags. You can also search using comma-separated pin IDs.": "Buscar términos para títulos de pin, descripciones o etiquetas. También puede buscar usando IDs de pines separados por comas.",
"Bookmark token from previous search results for pagination.": "Ficha de marcadores de resultados de búsqueda anteriores para la paginación.",
"Maximum number of pins to return (useful for large result sets).": "Número máximo de pines a devolver (útil para conjuntos de resultados grandes).",
"The new name of the board (max 180 characters). Leave empty to keep current name.": "El nuevo nombre del tablero (máximo 180 caracteres). Dejar en blanco para mantener el nombre actual.",
"The new description of the board (max 500 characters). Leave empty to keep current description.": "La nueva descripción del tablero (máximo 500 caracteres). Dejar en blanco para mantener la descripción actual.",
"Update board privacy setting. Leave empty to keep current setting.": "Actualizar configuración de privacidad del foro. Dejar vacío para mantener la configuración actual.",
"Image URL": "URL de imagen",
"Base64 Image": "Imagen Base64",
"Video URL": "URL del vídeo",
"Public": "Público",
"Protected": "Protegido",
"Secret": "Secreto",
"New Board": "Nuevo foro",
"New Follower": "Nuevo Seguidor",
"New Pin on Board": "Nuevo Pin en Tablero",
"Fires when a new board is created in the account.": "Dispara cuando se crea un nuevo tablero en la cuenta.",
"Triggers when a user gains a new follower.": "Dispara cuando un usuario obtiene un nuevo seguidor.",
"Fires when a new Pin is added to a specific board.": "Dispara cuando se añade un nuevo Pin a un tablero específico.",
"Board Privacy Filter": "Filtro de privacidad del foro",
"Page Size": "Tamaño de página",
"Pin Types to Watch": "Anclar tipos a ver",
"Filter boards by privacy setting (optional).": "Filtrar tableros por configuración de privacidad (opcional).",
"Number of boards to fetch per page (1-250, default: 25).": "Número de tableros a buscar por página (1-250, por defecto: 25).",
"Filter by specific pin types. Leave empty to watch all types.": "Filtrar por tipos de pin específicos. Dejar en blanco para ver todos los tipos.",
"All Boards": "Todos los tableros",
"Public Only": "Sólo público",
"Protected Only": "Sólo Protegidos",
"Secret Only": "Sólo secretos",
"Public and Secret": "Público y secreto",
"Regular Pins": "Alfileres regulares",
"Video Pins": "Pines de vídeo",
"Shopping Pins": "Pins de compras",
"Carousel Pins": "Carousel Pins",
"Idea Pins": "Alfileres de idea"
}

View File

@@ -0,0 +1,90 @@
{
"Connect your Pinterest Business Account": "Connectez votre compte Pinterest Business",
"Create Pin": "Créer une broche",
"Create Board": "Créer un tableau",
"Delete Pin": "Supprimer la broche",
"Find Board by Name": "Trouver un tableau par nom",
"Find Pin by Title/Keyword": "Trouver l'épingle par titre/Mot-clé",
"Update Board": "Mettre à jour le tableau",
"Upload an image or video to create a new Pin on a board.": "Téléchargez une image ou une vidéo pour créer une nouvelle broche sur un tableau.",
"Create a new Pinterest board for organizing Pins.": "Créer un nouveau tableau Pinterest pour organiser les Pins.",
"Permanently delete a specific Pin.": "Supprimer définitivement une épingle spécifique.",
"Search for boards by name using Pinterest's search API.": "Rechercher des tableaux par nom en utilisant l'API de recherche de Pinterest.",
"Search for Pins using title, description, or keywords.": "Rechercher des épingles en utilisant le titre, la description ou les mots-clés.",
"Update a board's name, description, or privacy settings.": "Mettre à jour le nom, la description ou les paramètres de confidentialité d'un tableau.",
"Ad account Id": "Id du compte publicitaire",
"Board Id": "Identifiant du tableau",
"Board Section Id": "ID de la section du tableau",
"Title": "Titre de la feuille de calcul",
"Description": "Libellé",
"Media Source Type": "Type de Media Source",
"Media URL": "URL du média",
"Destination Link": "Lien de destination",
"Dominant Color": "Couleur dominante",
"Alt Text": "Texte Alt",
"Parent Pin ID": "ID de Pin parent",
"Sponsor ID": "ID du sponsor",
"Product Tags": "Balises de produit",
"Note": "Note",
"Is Removable": "Est amovible",
"Board Name": "Nom du tableau",
"Privacy": "Confidentialité",
"Ads Only Board": "Annonces uniquement sur le tableau",
"pin Id": "ID de la broche",
"Search Query": "Requête de recherche",
"Bookmark": "Marque-page",
"Pagination Bookmark": "Marque-page de pagination",
"Maximum Results": "Nombre maximum de résultats",
"The title of the Pin (max 100 characters).": "Le titre de la broche (max 100 caractères).",
"The description of the Pin (max 800 characters).": "La description de la broche (max 800 caractères).",
"The type of media source for the Pin.": "Le type de source de média pour l'épingle.",
"The URL of the image or video to upload. Must be a valid URL.": "L'URL de l'image ou de la vidéo à télécharger. Doit être une URL valide.",
"The destination URL that the Pin will link to when clicked.": "L'URL de destination vers laquelle l'épingle sera lorsqu'elle sera cliquée.",
"The dominant color of the Pin as a hex color code (e.g., \"#6E7874\").": "La couleur dominante de la broche en tant que code couleur hexadécimal (par exemple, \"#6E7874\").",
"Alternative text for accessibility and screen readers (max 500 characters).": "Texte alternatif pour l'accessibilité et les lecteurs d'écran (max 500 caractères).",
"The ID of the original Pin if this is a saved/repinned Pin.": "L'ID de la broche originale si c'est une broche enregistrée/repérée.",
"The sponsor account ID for paid partnership content. Available only to select users in closed beta.": "L'ID du compte du sponsor pour le contenu du partenariat payant. Disponible uniquement pour sélectionner les utilisateurs en bêta fermée.",
"Select one or more options": "Sélectionnez une ou plusieurs options",
"A private note for this Pin that only you can see.": "Une note privée pour cette broche que vous seul pouvez voir.",
"Set to true to create an ad-only Pin that can be easily removed.": "Réglez sur vrai pour créer une épingle publicitaire qui peut être facilement supprimée.",
"The name of the board (max 180 characters).": "Le nom du tableau (max 180 caractères).",
"Optional description for your board.": "Description facultative pour votre tableau.",
"Board privacy setting (auto-set to \"PROTECTED\" for ad-only boards).": "Réglage de la confidentialité de la carte (auto-réglé sur \"PROTECTED\" pour les cartes ad-only).",
"Create an ad-only board that can only store promotional Pins. Note: Board name will become \"Ad-only Pins\" and privacy will be set to \"PROTECTED\".": "Créer un tableau réservé aux publicités qui ne peut stocker que les épingles promotionnelles. Remarque : Le nom du tableau deviendra des épingles publicitaires uniquement et la confidentialité sera réglée sur \"PROTECTED\".",
"The search term to find boards (required).": "Le terme de recherche pour trouver des tableaux (obligatoire).",
"Pagination bookmark from previous response.": "Signet de pagination de la réponse précédente.",
"Search terms for pin titles, descriptions, or tags. You can also search using comma-separated pin IDs.": "Rechercher des termes pour les titres, les descriptions ou les étiquettes. Vous pouvez également effectuer une recherche en utilisant des identifiants d'épingles séparés par des virgules.",
"Bookmark token from previous search results for pagination.": "Marquer le jeton des résultats de recherche précédents pour la pagination.",
"Maximum number of pins to return (useful for large result sets).": "Nombre maximum de pins à retourner (utile pour les grands jeux de résultats).",
"The new name of the board (max 180 characters). Leave empty to keep current name.": "Le nouveau nom du tableau (max 180 caractères). Laisser vide pour conserver le nom courant.",
"The new description of the board (max 500 characters). Leave empty to keep current description.": "La nouvelle description du tableau (max 500 caractères). Laisser vide pour conserver la description actuelle.",
"Update board privacy setting. Leave empty to keep current setting.": "Mettre à jour le paramètre de confidentialité du forum. Laisser vide pour conserver le paramètre actuel.",
"Image URL": "URL de l'image",
"Base64 Image": "Image Base64",
"Video URL": "URL de la vidéo",
"Public": "Publique",
"Protected": "Protégé",
"Secret": "Secrète",
"New Board": "Nouveau tableau",
"New Follower": "Nouvel abonné",
"New Pin on Board": "Nouvelle broche sur la carte",
"Fires when a new board is created in the account.": "Tire quand un nouveau tableau est créé dans le compte.",
"Triggers when a user gains a new follower.": "Déclenche lorsqu'un utilisateur gagne un nouvel abonné.",
"Fires when a new Pin is added to a specific board.": "Tire quand une nouvelle broche est ajoutée à une carte spécifique.",
"Board Privacy Filter": "Filtre de confidentialité du tableau",
"Page Size": "Nombre d'élément",
"Pin Types to Watch": "Épingler les types à surveiller",
"Filter boards by privacy setting (optional).": "Filtrer les tableaux par paramètre de confidentialité (facultatif).",
"Number of boards to fetch per page (1-250, default: 25).": "Nombre de tableaux à récupérer par page (1-250, par défaut: 25).",
"Filter by specific pin types. Leave empty to watch all types.": "Filtrer par types d'épingles spécifiques. Laisser vide pour regarder tous les types.",
"All Boards": "Toutes les planches",
"Public Only": "Publique uniquement",
"Protected Only": "Protégé uniquement",
"Secret Only": "Secret uniquement",
"Public and Secret": "Public et secret",
"Regular Pins": "Épingles régulières",
"Video Pins": "Épingles vidéo",
"Shopping Pins": "Pins d'achat",
"Carousel Pins": "Carousel Pins",
"Idea Pins": "Épingles d'idées"
}

View File

@@ -0,0 +1,90 @@
{
"Connect your Pinterest Business Account": "Pinterest ビジネスアカウントに接続",
"Create Pin": "ピンを作成",
"Create Board": "ボードを作成",
"Delete Pin": "ピンを削除",
"Find Board by Name": "名前でボードを検索",
"Find Pin by Title/Keyword": "タイトル/キーワードでピンを検索",
"Update Board": "ボードを更新",
"Upload an image or video to create a new Pin on a board.": "ボードに新しいピンを作成するには、画像またはビデオをアップロードします。",
"Create a new Pinterest board for organizing Pins.": "新しい Pinterest ボードを作成してピンを整理します。",
"Permanently delete a specific Pin.": "特定のピンを完全に削除します。",
"Search for boards by name using Pinterest's search API.": "Pinterestの検索APIを使用してボードを名前で検索します。",
"Search for Pins using title, description, or keywords.": "タイトル、説明、キーワードを使用してピンを検索します。",
"Update a board's name, description, or privacy settings.": "ボードの名前、説明、またはプライバシー設定を更新します。",
"Ad account Id": "広告アカウントID",
"Board Id": "ボード ID",
"Board Section Id": "ボードセクションID",
"Title": "タイトル",
"Description": "説明",
"Media Source Type": "メディアソースタイプ",
"Media URL": "メディア URL",
"Destination Link": "リンク先先",
"Dominant Color": "支配的な色",
"Alt Text": "代替テキスト",
"Parent Pin ID": "親ピンID",
"Sponsor ID": "スポンサーID",
"Product Tags": "商品タグ",
"Note": "メモ",
"Is Removable": "取り外し可能",
"Board Name": "ボード名",
"Privacy": "プライバシー",
"Ads Only Board": "広告のみ ボード",
"pin Id": "ピン ID",
"Search Query": "検索クエリ",
"Bookmark": "ブックマーク",
"Pagination Bookmark": "ページングのブックマーク",
"Maximum Results": "最大結果",
"The title of the Pin (max 100 characters).": "ピンのタイトル (最大 100 文字)",
"The description of the Pin (max 800 characters).": "ピンの説明 (最大 800 文字)。",
"The type of media source for the Pin.": "ピンのメディアソースのタイプ。",
"The URL of the image or video to upload. Must be a valid URL.": "アップロードする画像または動画のURL。有効なURLである必要があります。",
"The destination URL that the Pin will link to when clicked.": "ピンがクリックされたときにリンクするリンク先URL。",
"The dominant color of the Pin as a hex color code (e.g., \"#6E7874\").": "16進カラーコードとしてのピンの支配的な色(例:\"#6E7874\")。",
"Alternative text for accessibility and screen readers (max 500 characters).": "アクセシビリティとスクリーンリーダーの代替テキスト(最大 500 文字)。",
"The ID of the original Pin if this is a saved/repinned Pin.": "保存済み/反復されたピンの場合、元のピンの ID です。",
"The sponsor account ID for paid partnership content. Available only to select users in closed beta.": "有料パートナーシップコンテンツのスポンサーアカウントID。クローズドベータでのユーザーのみ利用できます。",
"Select one or more options": "1つ以上のオプションを選択してください",
"A private note for this Pin that only you can see.": "あなただけが見ることができるこのピンのプライベートノート。",
"Set to true to create an ad-only Pin that can be easily removed.": "簡単に削除できる広告のみのピンを作成するには、true に設定します。",
"The name of the board (max 180 characters).": "ボードの名前 (最大 180 文字)。",
"Optional description for your board.": "あなたのボードの任意の説明。",
"Board privacy setting (auto-set to \"PROTECTED\" for ad-only boards).": "ボードのプライバシー設定 (広告専用ボードの「保護」に自動設定)。",
"Create an ad-only board that can only store promotional Pins. Note: Board name will become \"Ad-only Pins\" and privacy will be set to \"PROTECTED\".": "プロモーションピンのみを格納できるアドオン専用ボードを作成します。注:ボード名は「アドオン専用ピン」になり、プライバシーは「保護」に設定されます。",
"The search term to find boards (required).": "ボードを検索するための検索語(必須)。",
"Pagination bookmark from previous response.": "以前の応答からのページネーションブックマーク。",
"Search terms for pin titles, descriptions, or tags. You can also search using comma-separated pin IDs.": "ピンのタイトル、説明、タグを検索します。カンマ区切りのピンIDを使用して検索することもできます。",
"Bookmark token from previous search results for pagination.": "ページネーション用に以前の検索結果のブックマークトークン。",
"Maximum number of pins to return (useful for large result sets).": "リターンする最大ピン数(大きな結果セットに便利)。",
"The new name of the board (max 180 characters). Leave empty to keep current name.": "ボードの新しい名前 (最大 180 文字) 。現在の名前を保持するには空白のままにします。",
"The new description of the board (max 500 characters). Leave empty to keep current description.": "ボードの新しい説明最大500文字。現在の説明を維持するには空のままにしてください。",
"Update board privacy setting. Leave empty to keep current setting.": "ボードのプライバシー設定を更新します。空のままにすると現在の設定を維持します。",
"Image URL": "画像URL",
"Base64 Image": "Base64 画像",
"Video URL": "動画の URL",
"Public": "公開",
"Protected": "保護",
"Secret": "シークレット",
"New Board": "新しいボード",
"New Follower": "新しいフォロワー",
"New Pin on Board": "ボード上の新しいピン",
"Fires when a new board is created in the account.": "アカウントに新しいボードが作成されたときに発火します。",
"Triggers when a user gains a new follower.": "ユーザーが新しいフォロワーを獲得したときにトリガーします。",
"Fires when a new Pin is added to a specific board.": "新しいピンが特定のボードに追加されたときに発生します。",
"Board Privacy Filter": "ボードプライバシーフィルタ",
"Page Size": "ページサイズ",
"Pin Types to Watch": "ウォッチにピンタイプ",
"Filter boards by privacy setting (optional).": "プライバシー設定でボードを絞り込みます (オプション)。",
"Number of boards to fetch per page (1-250, default: 25).": "ページごとにフェッチするボードの数1-250、デフォルト25",
"Filter by specific pin types. Leave empty to watch all types.": "特定のピンタイプでフィルタします。すべてのタイプを見るには空のままにします。",
"All Boards": "すべてのボード",
"Public Only": "公開のみ",
"Protected Only": "保護されたのみ",
"Secret Only": "シークレットのみ",
"Public and Secret": "公開と秘密",
"Regular Pins": "レギュラーピン",
"Video Pins": "ビデオピン",
"Shopping Pins": "ショッピングピン",
"Carousel Pins": "Carousel Pins",
"Idea Pins": "アイディアピン"
}

View File

@@ -0,0 +1,90 @@
{
"Connect your Pinterest Business Account": "Verbind uw Pinterest Business Account",
"Create Pin": "Pincode maken",
"Create Board": "Creëer bord",
"Delete Pin": "Verwijder PIN",
"Find Board by Name": "Zoek bord op naam",
"Find Pin by Title/Keyword": "Zoek PIN op Titel/Sleutelwoord",
"Update Board": "Bord bijwerken",
"Upload an image or video to create a new Pin on a board.": "Upload een afbeelding of video om een nieuwe pin op een bord te maken.",
"Create a new Pinterest board for organizing Pins.": "Maak een nieuw Pinterest board voor het organiseren van Pins.",
"Permanently delete a specific Pin.": "Een specifieke pin permanent verwijderen.",
"Search for boards by name using Pinterest's search API.": "Zoek boards op naam met behulp van Pinterest's zoekAPI.",
"Search for Pins using title, description, or keywords.": "Zoek naar pinnen met titel, beschrijving of trefwoorden.",
"Update a board's name, description, or privacy settings.": "Werk de naam van een bord of privacy instellingen bij.",
"Ad account Id": "Advertentie account-ID",
"Board Id": "Bord ID",
"Board Section Id": "Sectie-ID Bord",
"Title": "Aanspreektitel",
"Description": "Beschrijving",
"Media Source Type": "Media Source Type",
"Media URL": "Media URL",
"Destination Link": "Bestemming Link",
"Dominant Color": "Dominante Kleur",
"Alt Text": "Alternatieve tekst",
"Parent Pin ID": "Bovenliggende pin ID",
"Sponsor ID": "Sponsor ID",
"Product Tags": "Product tags",
"Note": "Notitie",
"Is Removable": "Is verwijderbaar",
"Board Name": "Naam bord",
"Privacy": "Privacy",
"Ads Only Board": "Alleen advertenties",
"pin Id": "pin ID",
"Search Query": "Zoek query",
"Bookmark": "Bladwijzer",
"Pagination Bookmark": "Paginering Bookmark",
"Maximum Results": "Maximaal aantal resultaten",
"The title of the Pin (max 100 characters).": "De titel van de pin (max 100 tekens).",
"The description of the Pin (max 800 characters).": "De beschrijving van de pin (max 800 tekens).",
"The type of media source for the Pin.": "Het mediabron voor de Pin.",
"The URL of the image or video to upload. Must be a valid URL.": "De URL van de afbeelding of video om te uploaden. Moet een geldige URL zijn.",
"The destination URL that the Pin will link to when clicked.": "De doel-URL waarnaar de PIN linkt wanneer geklikt wordt.",
"The dominant color of the Pin as a hex color code (e.g., \"#6E7874\").": "De dominante kleur van de pincode als hex kleurcode (bijv. \"#6E7874\").",
"Alternative text for accessibility and screen readers (max 500 characters).": "Alternatieve tekst voor toegankelijkheid en schermlezers (max 500 tekens).",
"The ID of the original Pin if this is a saved/repinned Pin.": "Het ID van de originele PIN als dit een opgeslagen/gerepareerde PIN is.",
"The sponsor account ID for paid partnership content. Available only to select users in closed beta.": "De sponsor account ID voor betaalde partnerschap inhoud. Alleen beschikbaar voor gebruikers in gesloten beta.",
"Select one or more options": "Selecteer een of meer opties",
"A private note for this Pin that only you can see.": "Een privénotitie voor deze pin die alleen u kunt zien.",
"Set to true to create an ad-only Pin that can be easily removed.": "Zet op true om een alleen-kladblok te maken die gemakkelijk kan worden verwijderd.",
"The name of the board (max 180 characters).": "De naam van het bord (max 180 tekens).",
"Optional description for your board.": "Optionele beschrijving voor jouw bord.",
"Board privacy setting (auto-set to \"PROTECTED\" for ad-only boards).": "Bord privacy-instelling (automatisch ingesteld op \"PROTECTED\" voor reclameborden).",
"Create an ad-only board that can only store promotional Pins. Note: Board name will become \"Ad-only Pins\" and privacy will be set to \"PROTECTED\".": "Creëer een enkel advertentiebord dat alleen promotionele pinnen kan opslaan. Opmerking: Bordentnaam wordt \"Ad-only Pins\" en privacy wordt ingesteld op \"PROTECTED\".",
"The search term to find boards (required).": "De zoekterm om boards te vinden (vereist).",
"Pagination bookmark from previous response.": "Paginering bladwijzer van het vorige antwoord.",
"Search terms for pin titles, descriptions, or tags. You can also search using comma-separated pin IDs.": "Zoektermen voor pin titels, beschrijvingen of tags. U kunt ook zoeken met behulp van komma-gescheiden pin IDs.",
"Bookmark token from previous search results for pagination.": "Bladwijzer token uit vorige zoekresultaten voor paginering.",
"Maximum number of pins to return (useful for large result sets).": "Maximum aantal te retourneren pinnen (nuttig voor grote resultaatsets).",
"The new name of the board (max 180 characters). Leave empty to keep current name.": "De nieuwe naam van het bord (max 180 tekens). Laat leeg om de huidige naam te bewaren.",
"The new description of the board (max 500 characters). Leave empty to keep current description.": "De nieuwe beschrijving van het bord (max 500 tekens). Laat leeg om de huidige beschrijving te behouden.",
"Update board privacy setting. Leave empty to keep current setting.": "Update board privacy instelling. Laat leeg om de huidige instelling te behouden.",
"Image URL": "Afbeelding URL",
"Base64 Image": "Base64 afbeelding",
"Video URL": "Video URL",
"Public": "Openbaar",
"Protected": "Beschermd",
"Secret": "Geheim",
"New Board": "Nieuw bord",
"New Follower": "Nieuwe volger",
"New Pin on Board": "Nieuwe pin op bord",
"Fires when a new board is created in the account.": "Schiet wanneer een nieuw bord wordt aangemaakt in het account.",
"Triggers when a user gains a new follower.": "Triggert wanneer een gebruiker een nieuwe volger krijgt.",
"Fires when a new Pin is added to a specific board.": "Vuurt wanneer een nieuwe pin is toegevoegd aan een specifiek bord.",
"Board Privacy Filter": "Bord privacyfilter",
"Page Size": "Paginagrootte",
"Pin Types to Watch": "Typ typen om te bekijken",
"Filter boards by privacy setting (optional).": "Filter boards op privacy-instelling (optioneel).",
"Number of boards to fetch per page (1-250, default: 25).": "Aantal boards dat per pagina moet worden opgehaald (1-250, standaard: 25).",
"Filter by specific pin types. Leave empty to watch all types.": "Filter op specifieke pintypes. Laat leeg om alle typen te bekijken.",
"All Boards": "Alle boards",
"Public Only": "Alleen openbaar",
"Protected Only": "Alleen beschermd",
"Secret Only": "Alleen geheim",
"Public and Secret": "Openbaar en geheim",
"Regular Pins": "Normale pinnen",
"Video Pins": "Video pinnen",
"Shopping Pins": "Winkel pinnen",
"Carousel Pins": "Carousel Pins",
"Idea Pins": "Idee pinnen"
}

View File

@@ -0,0 +1,90 @@
{
"Connect your Pinterest Business Account": "Conecte sua conta empresarial do Pinterest",
"Create Pin": "Criar PIN",
"Create Board": "Criar Board",
"Delete Pin": "Excluir Pin",
"Find Board by Name": "Encontrar Board por Nome",
"Find Pin by Title/Keyword": "Encontre o Pin por Título/Palavra-chave",
"Update Board": "Atualizar Board",
"Upload an image or video to create a new Pin on a board.": "Enviar uma imagem ou vídeo para criar um novo pin na lousa.",
"Create a new Pinterest board for organizing Pins.": "Criar um novo quadro do Pinterest para organizar Pins.",
"Permanently delete a specific Pin.": "Exclua permanentemente um pin específico.",
"Search for boards by name using Pinterest's search API.": "Busca por boards por nome usando a API de busca do Pinterest.",
"Search for Pins using title, description, or keywords.": "Pesquise por Pins usando título, descrição ou palavras-chave.",
"Update a board's name, description, or privacy settings.": "Atualizar o nome, descrição ou configurações de privacidade de um fórum.",
"Ad account Id": "ID da conta de anúncio",
"Board Id": "ID do fórum",
"Board Section Id": "ID da seção Board",
"Title": "Título",
"Description": "Descrição",
"Media Source Type": "Tipo de Fonte de Mídia",
"Media URL": "URL da Mídia",
"Destination Link": "Link de destino",
"Dominant Color": "Cor do Dominante",
"Alt Text": "Texto Alternativo",
"Parent Pin ID": "ID Pin Pai",
"Sponsor ID": "ID do Patrocinador",
"Product Tags": "Tags de Produto",
"Note": "Observação",
"Is Removable": "É removível",
"Board Name": "Nome do quadro",
"Privacy": "Privacidade",
"Ads Only Board": "Área de anúncios",
"pin Id": "ID do pin",
"Search Query": "Consulta de Pesquisa",
"Bookmark": "Favorito",
"Pagination Bookmark": "Marcador de Paginação",
"Maximum Results": "Resultados máximos",
"The title of the Pin (max 100 characters).": "O título do Pin (máx. 100 caracteres).",
"The description of the Pin (max 800 characters).": "A descrição do Pin (máx. 800 caracteres).",
"The type of media source for the Pin.": "O tipo de fonte de mídia para o Pin.",
"The URL of the image or video to upload. Must be a valid URL.": "A URL da imagem ou vídeo para upload. Deve ser uma URL válida.",
"The destination URL that the Pin will link to when clicked.": "A URL de destino que o Pin irá vincular quando clicado.",
"The dominant color of the Pin as a hex color code (e.g., \"#6E7874\").": "A cor dominante do Pin como um código de cores hexadecimal (ex: \"#6E7874\").",
"Alternative text for accessibility and screen readers (max 500 characters).": "Texto alternativo para leitores de tela e acessibilidade (máximo de 500 caracteres).",
"The ID of the original Pin if this is a saved/repinned Pin.": "O ID do Pin original se isto é um Pin salvo/refixado.",
"The sponsor account ID for paid partnership content. Available only to select users in closed beta.": "O ID de conta de patrocinador para conteúdo pago de parceria. Disponível apenas para selecionar usuários em beta fechado.",
"Select one or more options": "Selecione uma ou mais opções",
"A private note for this Pin that only you can see.": "Uma nota privada para este Pin que só você pode ver.",
"Set to true to create an ad-only Pin that can be easily removed.": "Defina como verdadeiro para criar um Pin com apenas anúncios que pode ser facilmente removido.",
"The name of the board (max 180 characters).": "O nome do board (máximo de 180 caracteres).",
"Optional description for your board.": "Descrição opcional para seu fórum.",
"Board privacy setting (auto-set to \"PROTECTED\" for ad-only boards).": "Configurações de privacidade do fórum (auto-definir como \"PROTECTAD\" para quadros somente anúncios).",
"Create an ad-only board that can only store promotional Pins. Note: Board name will become \"Ad-only Pins\" and privacy will be set to \"PROTECTED\".": "Crie um board somente-anúncio que só pode armazenar Pins promocionais. Nota: O nome do Board se tornará \"Pins com apenas publicidade\" e a privacidade será definida como \"PROTECTADA\".",
"The search term to find boards (required).": "O termo da pesquisa para encontrar quadros (obrigatório).",
"Pagination bookmark from previous response.": "Marcador de paginação da resposta anterior.",
"Search terms for pin titles, descriptions, or tags. You can also search using comma-separated pin IDs.": "Termos de pesquisa para pin títulos, descrições ou tags. Você também pode procurar usando IDs de pin separados por vírgula.",
"Bookmark token from previous search results for pagination.": "Token de marcador dos resultados de pesquisa anteriores para paginação.",
"Maximum number of pins to return (useful for large result sets).": "Número máximo de pinos a retornar (útil para grandes conjuntos de resultados).",
"The new name of the board (max 180 characters). Leave empty to keep current name.": "O novo nome do board (máximo de 180 caracteres). Deixe em branco para manter o nome atual.",
"The new description of the board (max 500 characters). Leave empty to keep current description.": "A nova descrição do board (máx. 500 caracteres). Deixe em branco para manter a descrição atual.",
"Update board privacy setting. Leave empty to keep current setting.": "Atualize a configuração de privacidade do fórum. Deixe em branco para manter a configuração atual.",
"Image URL": "URL da imagem",
"Base64 Image": "Imagem Base64",
"Video URL": "URL do vídeo",
"Public": "Público",
"Protected": "Protegido",
"Secret": "Segredo",
"New Board": "Novo Conselho",
"New Follower": "Novo seguidor",
"New Pin on Board": "Novo Pin no Board",
"Fires when a new board is created in the account.": "aciona quando um novo quadro é criado na conta.",
"Triggers when a user gains a new follower.": "Dispara quando um usuário ganha um novo seguidor.",
"Fires when a new Pin is added to a specific board.": "Lança quando um novo Pin é adicionado a um quadro específico.",
"Board Privacy Filter": "Board Filtro de Privacidade",
"Page Size": "Tamanho da página",
"Pin Types to Watch": "Fixar Tipos para Assistir",
"Filter boards by privacy setting (optional).": "Filtrar quadros por configuração de privacidade (opcional).",
"Number of boards to fetch per page (1-250, default: 25).": "Número de boards para buscar por página (1-250, padrão: 25).",
"Filter by specific pin types. Leave empty to watch all types.": "Filtrar por tipos de pin específicos. Deixe em branco para assistir a todos os tipos.",
"All Boards": "Todas as Seções",
"Public Only": "Apenas Público",
"Protected Only": "Somente Protegido",
"Secret Only": "Apenas Segredo",
"Public and Secret": "Público e Segredo",
"Regular Pins": "Pins regulares",
"Video Pins": "Pins de vídeo",
"Shopping Pins": "Pins de Compras",
"Carousel Pins": "Carousel Pins",
"Idea Pins": "Fixos de Ideia"
}

View File

@@ -0,0 +1,90 @@
{
"Connect your Pinterest Business Account": "Connect your Pinterest Business Account",
"Create Pin": "Create Pin",
"Create Board": "Create Board",
"Delete Pin": "Delete Pin",
"Find Board by Name": "Find Board by Name",
"Find Pin by Title/Keyword": "Find Pin by Title/Keyword",
"Update Board": "Update Board",
"Upload an image or video to create a new Pin on a board.": "Upload an image or video to create a new Pin on a board.",
"Create a new Pinterest board for organizing Pins.": "Create a new Pinterest board for organizing Pins.",
"Permanently delete a specific Pin.": "Permanently delete a specific Pin.",
"Search for boards by name using Pinterest's search API.": "Search for boards by name using Pinterest's search API.",
"Search for Pins using title, description, or keywords.": "Search for Pins using title, description, or keywords.",
"Update a board's name, description, or privacy settings.": "Update a board's name, description, or privacy settings.",
"Ad account Id": "Ad account Id",
"Board Id": "Board Id",
"Board Section Id": "Board Section Id",
"Title": "Title",
"Description": "Description",
"Media Source Type": "Media Source Type",
"Media URL": "Media URL",
"Destination Link": "Destination Link",
"Dominant Color": "Dominant Color",
"Alt Text": "Alt Text",
"Parent Pin ID": "Parent Pin ID",
"Sponsor ID": "Sponsor ID",
"Product Tags": "Product Tags",
"Note": "Note",
"Is Removable": "Is Removable",
"Board Name": "Board Name",
"Privacy": "Privacy",
"Ads Only Board": "Ads Only Board",
"pin Id": "pin Id",
"Search Query": "Search Query",
"Bookmark": "Bookmark",
"Pagination Bookmark": "Pagination Bookmark",
"Maximum Results": "Maximum Results",
"The title of the Pin (max 100 characters).": "The title of the Pin (max 100 characters).",
"The description of the Pin (max 800 characters).": "The description of the Pin (max 800 characters).",
"The type of media source for the Pin.": "The type of media source for the Pin.",
"The URL of the image or video to upload. Must be a valid URL.": "The URL of the image or video to upload. Must be a valid URL.",
"The destination URL that the Pin will link to when clicked.": "The destination URL that the Pin will link to when clicked.",
"The dominant color of the Pin as a hex color code (e.g., \"#6E7874\").": "The dominant color of the Pin as a hex color code (e.g., \"#6E7874\").",
"Alternative text for accessibility and screen readers (max 500 characters).": "Alternative text for accessibility and screen readers (max 500 characters).",
"The ID of the original Pin if this is a saved/repinned Pin.": "The ID of the original Pin if this is a saved/repinned Pin.",
"The sponsor account ID for paid partnership content. Available only to select users in closed beta.": "The sponsor account ID for paid partnership content. Available only to select users in closed beta.",
"Select one or more options": "Select one or more options",
"A private note for this Pin that only you can see.": "A private note for this Pin that only you can see.",
"Set to true to create an ad-only Pin that can be easily removed.": "Set to true to create an ad-only Pin that can be easily removed.",
"The name of the board (max 180 characters).": "The name of the board (max 180 characters).",
"Optional description for your board.": "Optional description for your board.",
"Board privacy setting (auto-set to \"PROTECTED\" for ad-only boards).": "Board privacy setting (auto-set to \"PROTECTED\" for ad-only boards).",
"Create an ad-only board that can only store promotional Pins. Note: Board name will become \"Ad-only Pins\" and privacy will be set to \"PROTECTED\".": "Create an ad-only board that can only store promotional Pins. Note: Board name will become \"Ad-only Pins\" and privacy will be set to \"PROTECTED\".",
"The search term to find boards (required).": "The search term to find boards (required).",
"Pagination bookmark from previous response.": "Pagination bookmark from previous response.",
"Search terms for pin titles, descriptions, or tags. You can also search using comma-separated pin IDs.": "Search terms for pin titles, descriptions, or tags. You can also search using comma-separated pin IDs.",
"Bookmark token from previous search results for pagination.": "Bookmark token from previous search results for pagination.",
"Maximum number of pins to return (useful for large result sets).": "Maximum number of pins to return (useful for large result sets).",
"The new name of the board (max 180 characters). Leave empty to keep current name.": "The new name of the board (max 180 characters). Leave empty to keep current name.",
"The new description of the board (max 500 characters). Leave empty to keep current description.": "The new description of the board (max 500 characters). Leave empty to keep current description.",
"Update board privacy setting. Leave empty to keep current setting.": "Update board privacy setting. Leave empty to keep current setting.",
"Image URL": "Image URL",
"Base64 Image": "Base64 Image",
"Video URL": "Video URL",
"Public": "Public",
"Protected": "Protected",
"Secret": "Secret",
"New Board": "New Board",
"New Follower": "New Follower",
"New Pin on Board": "New Pin on Board",
"Fires when a new board is created in the account.": "Fires when a new board is created in the account.",
"Triggers when a user gains a new follower.": "Triggers when a user gains a new follower.",
"Fires when a new Pin is added to a specific board.": "Fires when a new Pin is added to a specific board.",
"Board Privacy Filter": "Board Privacy Filter",
"Page Size": "Page Size",
"Pin Types to Watch": "Pin Types to Watch",
"Filter boards by privacy setting (optional).": "Filter boards by privacy setting (optional).",
"Number of boards to fetch per page (1-250, default: 25).": "Number of boards to fetch per page (1-250, default: 25).",
"Filter by specific pin types. Leave empty to watch all types.": "Filter by specific pin types. Leave empty to watch all types.",
"All Boards": "All Boards",
"Public Only": "Public Only",
"Protected Only": "Protected Only",
"Secret Only": "Secret Only",
"Public and Secret": "Public and Secret",
"Regular Pins": "Regular Pins",
"Video Pins": "Video Pins",
"Shopping Pins": "Shopping Pins",
"Carousel Pins": "Carousel Pins",
"Idea Pins": "Idea Pins"
}

View File

@@ -0,0 +1,90 @@
{
"Connect your Pinterest Business Account": "Connect your Pinterest Business Account",
"Create Pin": "Create Pin",
"Create Board": "Create Board",
"Delete Pin": "Delete Pin",
"Find Board by Name": "Find Board by Name",
"Find Pin by Title/Keyword": "Find Pin by Title/Keyword",
"Update Board": "Update Board",
"Upload an image or video to create a new Pin on a board.": "Upload an image or video to create a new Pin on a board.",
"Create a new Pinterest board for organizing Pins.": "Create a new Pinterest board for organizing Pins.",
"Permanently delete a specific Pin.": "Permanently delete a specific Pin.",
"Search for boards by name using Pinterest's search API.": "Search for boards by name using Pinterest's search API.",
"Search for Pins using title, description, or keywords.": "Search for Pins using title, description, or keywords.",
"Update a board's name, description, or privacy settings.": "Update a board's name, description, or privacy settings.",
"Ad account Id": "Ad account Id",
"Board Id": "Board Id",
"Board Section Id": "Board Section Id",
"Title": "标题",
"Description": "描述",
"Media Source Type": "Media Source Type",
"Media URL": "Media URL",
"Destination Link": "Destination Link",
"Dominant Color": "Dominant Color",
"Alt Text": "Alt Text",
"Parent Pin ID": "Parent Pin ID",
"Sponsor ID": "Sponsor ID",
"Product Tags": "Product Tags",
"Note": "说明",
"Is Removable": "Is Removable",
"Board Name": "Board Name",
"Privacy": "Privacy",
"Ads Only Board": "Ads Only Board",
"pin Id": "pin Id",
"Search Query": "Search Query",
"Bookmark": "Bookmark",
"Pagination Bookmark": "Pagination Bookmark",
"Maximum Results": "Maximum Results",
"The title of the Pin (max 100 characters).": "The title of the Pin (max 100 characters).",
"The description of the Pin (max 800 characters).": "The description of the Pin (max 800 characters).",
"The type of media source for the Pin.": "The type of media source for the Pin.",
"The URL of the image or video to upload. Must be a valid URL.": "The URL of the image or video to upload. Must be a valid URL.",
"The destination URL that the Pin will link to when clicked.": "The destination URL that the Pin will link to when clicked.",
"The dominant color of the Pin as a hex color code (e.g., \"#6E7874\").": "The dominant color of the Pin as a hex color code (e.g., \"#6E7874\").",
"Alternative text for accessibility and screen readers (max 500 characters).": "Alternative text for accessibility and screen readers (max 500 characters).",
"The ID of the original Pin if this is a saved/repinned Pin.": "The ID of the original Pin if this is a saved/repinned Pin.",
"The sponsor account ID for paid partnership content. Available only to select users in closed beta.": "The sponsor account ID for paid partnership content. Available only to select users in closed beta.",
"Select one or more options": "Select one or more options",
"A private note for this Pin that only you can see.": "A private note for this Pin that only you can see.",
"Set to true to create an ad-only Pin that can be easily removed.": "Set to true to create an ad-only Pin that can be easily removed.",
"The name of the board (max 180 characters).": "The name of the board (max 180 characters).",
"Optional description for your board.": "Optional description for your board.",
"Board privacy setting (auto-set to \"PROTECTED\" for ad-only boards).": "Board privacy setting (auto-set to \"PROTECTED\" for ad-only boards).",
"Create an ad-only board that can only store promotional Pins. Note: Board name will become \"Ad-only Pins\" and privacy will be set to \"PROTECTED\".": "Create an ad-only board that can only store promotional Pins. Note: Board name will become \"Ad-only Pins\" and privacy will be set to \"PROTECTED\".",
"The search term to find boards (required).": "The search term to find boards (required).",
"Pagination bookmark from previous response.": "Pagination bookmark from previous response.",
"Search terms for pin titles, descriptions, or tags. You can also search using comma-separated pin IDs.": "Search terms for pin titles, descriptions, or tags. You can also search using comma-separated pin IDs.",
"Bookmark token from previous search results for pagination.": "Bookmark token from previous search results for pagination.",
"Maximum number of pins to return (useful for large result sets).": "Maximum number of pins to return (useful for large result sets).",
"The new name of the board (max 180 characters). Leave empty to keep current name.": "The new name of the board (max 180 characters). Leave empty to keep current name.",
"The new description of the board (max 500 characters). Leave empty to keep current description.": "The new description of the board (max 500 characters). Leave empty to keep current description.",
"Update board privacy setting. Leave empty to keep current setting.": "Update board privacy setting. Leave empty to keep current setting.",
"Image URL": "Image URL",
"Base64 Image": "Base64 Image",
"Video URL": "Video URL",
"Public": "Public",
"Protected": "Protected",
"Secret": "Secret",
"New Board": "New Board",
"New Follower": "New Follower",
"New Pin on Board": "New Pin on Board",
"Fires when a new board is created in the account.": "Fires when a new board is created in the account.",
"Triggers when a user gains a new follower.": "Triggers when a user gains a new follower.",
"Fires when a new Pin is added to a specific board.": "Fires when a new Pin is added to a specific board.",
"Board Privacy Filter": "Board Privacy Filter",
"Page Size": "Page Size",
"Pin Types to Watch": "Pin Types to Watch",
"Filter boards by privacy setting (optional).": "Filter boards by privacy setting (optional).",
"Number of boards to fetch per page (1-250, default: 25).": "Number of boards to fetch per page (1-250, default: 25).",
"Filter by specific pin types. Leave empty to watch all types.": "Filter by specific pin types. Leave empty to watch all types.",
"All Boards": "All Boards",
"Public Only": "Public Only",
"Protected Only": "Protected Only",
"Secret Only": "Secret Only",
"Public and Secret": "Public and Secret",
"Regular Pins": "Regular Pins",
"Video Pins": "Video Pins",
"Shopping Pins": "Shopping Pins",
"Carousel Pins": "Carousel Pins",
"Idea Pins": "Idea Pins"
}

View File

@@ -0,0 +1,28 @@
import { createPiece } from '@activepieces/pieces-framework';
import { pinterestAuth } from './lib/common/auth';
import { createPin } from './lib/actions/create-pin';
import { createBoard } from './lib/actions/create-board';
import { deletePin } from './lib/actions/delete-pin';
import { findBoardByName } from './lib/actions/find-board-by-name';
import { findPin } from './lib/actions/find-pin';
import { updateBoard } from './lib/actions/update-board';
import { newBoard } from './lib/triggers/new-board';
import { newFollower } from './lib/triggers/new-follower';
import { newPinOnBoard } from './lib/triggers/new-pin-on-board';
export const pinterest = createPiece({
displayName: 'Pinterest',
auth: pinterestAuth,
minimumSupportedRelease: '0.36.1',
logoUrl: 'https://cdn.activepieces.com/pieces/pinterest.png',
authors: ['Sanket6652'],
actions: [
createPin,
createBoard,
deletePin,
findBoardByName,
findPin,
updateBoard,
],
triggers: [newBoard, newFollower, newPinOnBoard],
});

View File

@@ -0,0 +1,80 @@
import {
createAction,
Property,
OAuth2PropertyValue,
} from '@activepieces/pieces-framework';
import { makeRequest } from '../common';
import { pinterestAuth } from '../common/auth';
import { HttpMethod, getAccessTokenOrThrow } from '@activepieces/pieces-common';
import { adAccountIdDropdown } from '../common/props';
export const createBoard = createAction({
auth: pinterestAuth,
name: 'createBoard',
displayName: 'Create Board',
description: 'Create a new Pinterest board for organizing Pins.',
props: {
ad_account_id: adAccountIdDropdown,
name: Property.ShortText({
displayName: 'Board Name',
required: true,
description: 'The name of the board (max 180 characters).',
}),
description: Property.LongText({
displayName: 'Description',
required: false,
description: 'Optional description for your board.',
}),
privacy: Property.StaticDropdown({
displayName: 'Privacy',
required: false,
defaultValue: 'PUBLIC',
options: {
options: [
{ label: 'Public', value: 'PUBLIC' },
{ label: 'Protected', value: 'PROTECTED' },
{ label: 'Secret', value: 'SECRET' },
],
},
description:
'Board privacy setting (auto-set to "PROTECTED" for ad-only boards).',
}),
is_ads_only: Property.Checkbox({
displayName: 'Ads Only Board',
description:
'Create an ad-only board that can only store promotional Pins. Note: Board name will become "Ad-only Pins" and privacy will be set to "PROTECTED".',
defaultValue: false,
required: false,
}),
},
async run({ auth, propsValue }) {
const { ad_account_id, name, description, privacy, is_ads_only } =
propsValue;
// Validation
if (name && name.length > 180) {
throw new Error('Board name must be 180 characters or less');
}
if (description && description.length > 500) {
throw new Error('Board description must be 500 characters or less');
}
const body: any = {
name,
is_ads_only,
};
if (description) body.description = description;
if (privacy) body.privacy = privacy;
let path = '/boards';
if (ad_account_id) {
path = `/boards?ad_account_id=${encodeURIComponent(ad_account_id)}`;
}
return await makeRequest(
getAccessTokenOrThrow(auth),
HttpMethod.POST,
path,
body
);
},
});

View File

@@ -0,0 +1,198 @@
import {
createAction,
Property,
OAuth2PropertyValue,
} from '@activepieces/pieces-framework';
import { makeRequest } from '../common';
import { pinterestAuth } from '../common/auth';
import { HttpMethod, getAccessTokenOrThrow } from '@activepieces/pieces-common';
import {
adAccountIdDropdown,
boardIdDropdown,
boardSectionIdDropdown,
pinIdMultiSelectDropdown,
} from '../common/props';
export const createPin = createAction({
auth: pinterestAuth,
name: 'createPin',
displayName: 'Create Pin',
description: 'Upload an image or video to create a new Pin on a board.',
props: {
ad_account_id: adAccountIdDropdown,
board_id: boardIdDropdown,
board_section_id: boardSectionIdDropdown,
title: Property.ShortText({
displayName: 'Title',
required: true,
description: 'The title of the Pin (max 100 characters).',
}),
description: Property.LongText({
displayName: 'Description',
required: false,
description: 'The description of the Pin (max 800 characters).',
}),
media_source_type: Property.StaticDropdown({
displayName: 'Media Source Type',
required: true,
description: 'The type of media source for the Pin.',
options: {
options: [
{ label: 'Image URL', value: 'image_url' },
{ label: 'Base64 Image', value: 'image_base64' },
{ label: 'Video URL', value: 'video_url' },
],
},
}),
media_url: Property.ShortText({
displayName: 'Media URL',
required: true,
description:
'The URL of the image or video to upload. Must be a valid URL.',
}),
link: Property.ShortText({
displayName: 'Destination Link',
required: false,
description:
'The destination URL that the Pin will link to when clicked.',
}),
dominant_color: Property.ShortText({
displayName: 'Dominant Color',
description:
'The dominant color of the Pin as a hex color code (e.g., "#6E7874").',
required: false,
}),
alt_text: Property.ShortText({
displayName: 'Alt Text',
description:
'Alternative text for accessibility and screen readers (max 500 characters).',
required: false,
}),
parent_pin_id: Property.ShortText({
displayName: 'Parent Pin ID',
description:
'The ID of the original Pin if this is a saved/repinned Pin.',
required: false,
}),
sponsor_id: Property.ShortText({
displayName: 'Sponsor ID',
description:
'The sponsor account ID for paid partnership content. Available only to select users in closed beta.',
required: false,
}),
product_tags: pinIdMultiSelectDropdown,
note: Property.ShortText({
displayName: 'Note',
description: 'A private note for this Pin that only you can see.',
required: false,
}),
is_removable: Property.Checkbox({
displayName: 'Is Removable',
description:
'Set to true to create an ad-only Pin that can be easily removed.',
required: false,
defaultValue: false,
}),
},
async run({ auth, propsValue }) {
const {
board_id,
board_section_id,
title,
description,
media_source_type,
media_url,
link,
dominant_color,
alt_text,
parent_pin_id,
is_removable,
product_tags,
ad_account_id,
note,
sponsor_id,
} = propsValue;
// Validation
if (title && title.length > 100) {
throw new Error('Title must be 100 characters or less');
}
if (description && description.length > 800) {
throw new Error('Description must be 800 characters or less');
}
if (alt_text && alt_text.length > 500) {
throw new Error('Alt text must be 500 characters or less');
}
// URL validation for media_url
try {
new URL(media_url);
} catch {
throw new Error('Please enter a valid URL for Image/Video URL');
}
// URL validation for link (if provided)
if (link) {
try {
new URL(link);
} catch {
throw new Error('Please enter a valid URL for Destination Link');
}
}
// Hex color validation for dominant_color (if provided)
if (dominant_color) {
const hexColorRegex = /^#[0-9A-Fa-f]{6}$/;
if (!hexColorRegex.test(dominant_color)) {
throw new Error(
'Pin Color must be a valid hex color format (e.g., #6E7874)'
);
}
}
// Build request body according to Pinterest API spec
const body: any = {
board_id,
title,
media_source: {
source_type: media_source_type,
url: media_url,
},
};
// Add optional fields only if they have values
if (board_section_id) body.board_section_id = board_section_id;
if (description) body.description = description;
if (link) body.link = link;
if (dominant_color) body.dominant_color = dominant_color;
if (alt_text) body.alt_text = alt_text;
if (parent_pin_id) body.parent_pin_id = parent_pin_id;
if (note) body.note = note;
if (sponsor_id) body.sponsor_id = sponsor_id;
if (typeof is_removable === 'boolean') body.is_removable = is_removable;
// Handle product_tags array
if (
product_tags &&
Array.isArray(product_tags) &&
product_tags.length > 0
) {
body.product_tags = product_tags;
}
// Build API path
let path = '/pins';
if (ad_account_id) {
path = `/pins?ad_account_id=${encodeURIComponent(ad_account_id)}`;
}
return await makeRequest(
getAccessTokenOrThrow(auth),
HttpMethod.POST,
path,
body
);
},
});

View File

@@ -0,0 +1,40 @@
import {
createAction,
Property,
OAuth2PropertyValue,
} from '@activepieces/pieces-framework';
import { makeRequest } from '../common';
import { pinterestAuth } from '../common/auth';
import { HttpMethod, getAccessTokenOrThrow } from '@activepieces/pieces-common';
import { adAccountIdDropdown, pinIdDropdown } from '../common/props';
export const deletePin = createAction({
auth: pinterestAuth,
name: 'deletePin',
displayName: 'Delete Pin',
description: 'Permanently delete a specific Pin.',
props: {
pin_id: pinIdDropdown,
ad_account_id: adAccountIdDropdown,
},
async run({ auth, propsValue }) {
const { pin_id, ad_account_id } = propsValue;
let path = `/pins/${pin_id}`;
if (ad_account_id) {
path = `/pins/${pin_id}?ad_account_id=${ad_account_id}`;
}
const response = await makeRequest(
getAccessTokenOrThrow(auth),
HttpMethod.DELETE,
path
);
return {
success: true,
message: `Pin ${pin_id} has been successfully deleted.`,
pin_id: pin_id,
};
},
});

View File

@@ -0,0 +1,62 @@
import {
createAction,
Property,
OAuth2PropertyValue,
} from '@activepieces/pieces-framework';
import { makeRequest } from '../common';
import { pinterestAuth } from '../common/auth';
import { HttpMethod, getAccessTokenOrThrow } from '@activepieces/pieces-common';
import { adAccountIdDropdown } from '../common/props';
export const findBoardByName = createAction({
auth: pinterestAuth,
name: 'findBoardByName',
displayName: 'Find Board by Name',
description: "Search for boards by name using Pinterest's search API.",
props: {
query: Property.ShortText({
displayName: 'Search Query',
required: true,
description: 'The search term to find boards (required).',
}),
ad_account_id: adAccountIdDropdown,
bookmark: Property.ShortText({
displayName: 'Bookmark',
required: false,
description: 'Pagination bookmark from previous response.',
}),
},
async run({ auth, propsValue }) {
const { query, ad_account_id, bookmark } = propsValue;
// Build query parameters
const searchParams = new URLSearchParams();
searchParams.append('query', query);
if (ad_account_id) {
searchParams.append('ad_account_id', ad_account_id);
}
if (bookmark) {
searchParams.append('bookmark', bookmark);
}
const path = `/search/boards/?${searchParams.toString()}`;
try {
const response = await makeRequest(
getAccessTokenOrThrow(auth),
HttpMethod.GET,
path
);
return response;
} catch (error) {
throw new Error(
`Failed to search boards: ${
error instanceof Error ? error.message : 'Unknown error'
}`
);
}
},
});

View File

@@ -0,0 +1,84 @@
import {
createAction,
Property,
OAuth2PropertyValue,
} from '@activepieces/pieces-framework';
import { makeRequest } from '../common';
import { pinterestAuth } from '../common/auth';
import { HttpMethod, getAccessTokenOrThrow } from '@activepieces/pieces-common';
import { adAccountIdDropdown } from '../common/props';
export const findPin = createAction({
auth: pinterestAuth,
name: 'findPin',
displayName: 'Find Pin by Title/Keyword',
description: 'Search for Pins using title, description, or keywords.',
props: {
ad_account_id: adAccountIdDropdown,
query: Property.ShortText({
displayName: 'Search Query',
required: true,
description:
'Search terms for pin titles, descriptions, or tags. You can also search using comma-separated pin IDs.',
}),
bookmark: Property.ShortText({
displayName: 'Pagination Bookmark',
required: false,
description:
'Bookmark token from previous search results for pagination.',
}),
max_results: Property.Number({
displayName: 'Maximum Results',
required: false,
description:
'Maximum number of pins to return (useful for large result sets).',
defaultValue: 25,
}),
},
async run({ auth, propsValue }) {
const { query, bookmark, ad_account_id, max_results } = propsValue;
// Build query parameters
const params = new URLSearchParams();
params.append('query', query);
if (bookmark) {
params.append('bookmark', bookmark);
}
if (ad_account_id) {
params.append('ad_account_id', ad_account_id);
}
const path = `/search/pins?${params.toString()}`;
try {
const response = await makeRequest(
getAccessTokenOrThrow(auth),
HttpMethod.GET,
path
);
// Apply max_results limit if specified
let items = response.items || [];
if (max_results && items.length > max_results) {
items = items.slice(0, max_results);
}
return {
items,
bookmark: response.bookmark,
total_results: items.length,
query_used: query,
has_more: !!response.bookmark,
};
} catch (error: any) {
if (error.response?.status === 404) {
throw new Error('No pins found matching your search criteria.');
}
throw new Error(
`Failed to search pins: ${error.message || 'Unknown error'}`
);
}
},
});

View File

@@ -0,0 +1,99 @@
import {
createAction,
Property,
OAuth2PropertyValue,
} from '@activepieces/pieces-framework';
import { makeRequest } from '../common';
import { pinterestAuth } from '../common/auth';
import { HttpMethod, getAccessTokenOrThrow } from '@activepieces/pieces-common';
import { adAccountIdDropdown, boardIdDropdown } from '../common/props';
export const updateBoard = createAction({
auth: pinterestAuth,
name: 'updateBoard',
displayName: 'Update Board',
description: "Update a board's name, description, or privacy settings.",
props: {
board_id: boardIdDropdown,
ad_account_id: adAccountIdDropdown,
name: Property.ShortText({
displayName: 'Board Name',
required: false,
description:
'The new name of the board (max 180 characters). Leave empty to keep current name.',
}),
description: Property.LongText({
displayName: 'Description',
required: false,
description:
'The new description of the board (max 500 characters). Leave empty to keep current description.',
}),
privacy: Property.StaticDropdown({
displayName: 'Privacy',
required: false,
options: {
options: [
{ label: 'Public', value: 'PUBLIC' },
{ label: 'Protected', value: 'PROTECTED' },
{ label: 'Secret', value: 'SECRET' },
],
},
description:
'Update board privacy setting. Leave empty to keep current setting.',
}),
},
async run({ auth, propsValue }) {
const { board_id, name, description, privacy, ad_account_id } = propsValue;
// Validation - at least one field must be provided for update
if (!name && description === undefined && !privacy) {
throw new Error(
'At least one field (name, description, or privacy) must be provided to update the board.'
);
}
// Validation for field lengths
if (name && name.length > 180) {
throw new Error('Board name must be 180 characters or less');
}
if (description && description.length > 500) {
throw new Error('Board description must be 500 characters or less');
}
// Build request body with only the fields being updated
const body: any = {};
if (name && name.trim()) {
body.name = name.trim();
}
if (description !== undefined) {
body.description = description;
}
if (privacy) {
body.privacy = privacy;
}
// Build path with query parameter if ad_account_id is provided
let path = `/boards/${board_id}`;
if (ad_account_id) {
path = `/boards/${board_id}?ad_account_id=${encodeURIComponent(
ad_account_id
)}`;
}
try {
return await makeRequest(
getAccessTokenOrThrow(auth),
HttpMethod.PATCH,
path,
body
);
} catch (error) {
throw new Error(
`Failed to update board: ${
error instanceof Error ? error.message : 'Unknown error'
}`
);
}
},
});

View File

@@ -0,0 +1,22 @@
import {
PieceAuth,
OAuth2AuthorizationMethod,
} from '@activepieces/pieces-framework';
export const pinterestAuth = PieceAuth.OAuth2({
description: 'Connect your Pinterest Business Account',
authUrl: 'https://www.pinterest.com/oauth/',
tokenUrl: 'https://api.pinterest.com/v5/oauth/token',
required: true,
scope: [
'ads:read',
'boards:read',
'boards:write',
'boards:read_secret',
'pins:read',
'pins:write',
'pins:read_secret',
'user_accounts:read',
],
authorizationMethod: OAuth2AuthorizationMethod.HEADER,
});

View File

@@ -0,0 +1,104 @@
import { HttpMethod, httpClient } from '@activepieces/pieces-common';
export const BASE_URL = 'https://api.pinterest.com/v5';
export async function makeRequest(
apiKey: string,
method: HttpMethod,
path: string,
body?: unknown
) {
try {
const response = await httpClient.sendRequest({
method,
url: `${BASE_URL}${path}`,
headers: {
Authorization: `Bearer ${apiKey}`,
'Content-Type': 'application/json',
},
body,
});
return response.body;
} catch (error: any) {
// Handle Pinterest API specific error codes
if (error.response?.status) {
const status = error.response.status;
const errorData = error.response.body;
switch (status) {
case 400:
throw new Error(
`Bad Request: ${
errorData?.message ||
'Invalid request parameters. Please check your input and try again.'
}`
);
case 401:
throw new Error(
'Authentication Failed: Your Pinterest access token is invalid or expired. Please reconnect your Pinterest account.'
);
case 403:
throw new Error(
"Access Denied: You don't have permission to access this resource. Please check your Pinterest account permissions."
);
case 404:
throw new Error(
'Resource Not Found: The requested Pinterest resource (board, pin, etc.) could not be found. Please verify the resource exists.'
);
case 429:
throw new Error(
"Rate Limit Exceeded: You've exceeded Pinterest's API rate limits. Please wait a moment and try again."
);
case 500:
throw new Error(
"Pinterest Server Error: Pinterest's servers are experiencing issues. Please try again later."
);
case 502:
throw new Error(
"Bad Gateway: Pinterest's servers are temporarily unavailable. Please try again later."
);
case 503:
throw new Error(
"Service Unavailable: Pinterest's API service is temporarily down. Please try again later."
);
default:
throw new Error(
`Pinterest API Error (${status}): ${
errorData?.message ||
'An unexpected error occurred while communicating with Pinterest.'
}`
);
}
}
// Handle network or other errors
if (error.code === 'ECONNREFUSED' || error.code === 'ENOTFOUND') {
throw new Error(
'Network Error: Unable to connect to Pinterest API. Please check your internet connection and try again.'
);
}
if (error.code === 'ETIMEDOUT') {
throw new Error(
'Request Timeout: The request to Pinterest API timed out. Please try again.'
);
}
// Generic error fallback
throw new Error(
`Unexpected Error: ${
error.message ||
'An unexpected error occurred while processing your request.'
}`
);
}
}

View File

@@ -0,0 +1,225 @@
import {
DropdownOption,
Property,
OAuth2PropertyValue,
} from '@activepieces/pieces-framework';
import { makeRequest } from '.';
import { HttpMethod, getAccessTokenOrThrow } from '@activepieces/pieces-common';
import { pinterestAuth } from './auth';
export const boardIdDropdown = Property.Dropdown({
auth: pinterestAuth,
displayName: 'Board Id',
required: true,
refreshers: ['ad_account_id'],
options: async ({ auth, ad_account_id }) => {
if (!auth) {
return {
disabled: true,
placeholder: 'Please connect your account',
options: [],
};
}
try {
const url = new URL('/boards', 'https://api.pinterest.com/v5');
if (ad_account_id) {
url.searchParams.append('ad_account_id', ad_account_id as string);
}
const accessToken = getAccessTokenOrThrow(auth as OAuth2PropertyValue);
const boards = await makeRequest(
accessToken,
HttpMethod.GET,
url.pathname + url.search
);
const options: DropdownOption<string>[] = boards.items.map(
(board: any) => ({
label: board.name,
value: board.id,
})
);
return {
disabled: false,
options,
};
} catch (error) {
return {
disabled: true,
placeholder: 'Error loading boards. Please try again.',
options: [],
};
}
},
});
export const pinIdDropdown = Property.Dropdown({
auth: pinterestAuth,
displayName: 'pin Id',
required: true,
refreshers: ['auth'],
options: async ({ auth }) => {
if (!auth) {
return {
disabled: true,
placeholder: 'Please connect your account',
options: [],
};
}
try {
const accessToken = getAccessTokenOrThrow(auth as OAuth2PropertyValue);
const pins = await makeRequest(accessToken, HttpMethod.GET, '/pins');
const options: DropdownOption<string>[] = pins.items.map((pin: any) => ({
label: pin.title,
value: pin.id,
}));
return {
disabled: false,
options,
};
} catch (error) {
return {
disabled: true,
placeholder: 'Error loading pins. Please try again.',
options: [],
};
}
},
});
export const adAccountIdDropdown = Property.Dropdown({
auth: pinterestAuth,
displayName: 'Ad account Id',
required: false,
refreshers: ['auth'],
options: async ({ auth }) => {
if (!auth) {
return {
disabled: true,
placeholder: 'Please connect your account',
options: [],
};
}
try {
const accessToken = getAccessTokenOrThrow(auth as OAuth2PropertyValue);
const adAccounts = await makeRequest(
accessToken,
HttpMethod.GET,
'/ad_accounts'
);
const options: DropdownOption<string>[] = adAccounts.items.map(
(account: any) => ({
label: account.name,
value: account.id,
})
);
return {
disabled: false,
options,
};
} catch (error) {
return {
disabled: true,
placeholder: 'Error loading ad accounts. Please try again.',
options: [],
};
}
},
});
export const boardSectionIdDropdown = Property.Dropdown({
auth: pinterestAuth,
displayName: 'Board Section Id',
required: false,
refreshers: ['auth', 'board_id'],
options: async ({ auth, board_id }) => {
if (!auth) {
return {
disabled: true,
placeholder: 'Please connect your account',
options: [],
};
}
if (!board_id) {
return {
disabled: true,
placeholder: 'Please select a board first',
options: [],
};
}
try {
const accessToken = getAccessTokenOrThrow(auth as OAuth2PropertyValue);
const boardsections = await makeRequest(
accessToken,
HttpMethod.GET,
`/boards/${board_id}/sections`
);
const options: DropdownOption<string>[] = boardsections.items.map(
(section: any) => ({
label: section.name,
value: section.id,
})
);
return {
disabled: false,
options,
};
} catch (error) {
return {
disabled: true,
placeholder: 'Error loading board sections. Please try again.',
options: [],
};
}
},
});
export const pinIdMultiSelectDropdown = Property.MultiSelectDropdown({
auth: pinterestAuth,
displayName: 'Product Tags',
description: 'Select one or more options',
required: false,
refreshers: ['auth'],
options: async ({ auth }) => {
if (!auth) {
return {
disabled: true,
placeholder: 'Please connect your account',
options: [],
};
}
try {
const accessToken = getAccessTokenOrThrow(auth as OAuth2PropertyValue);
const pins = await makeRequest(accessToken, HttpMethod.GET, '/pins');
const options: DropdownOption<string>[] = pins.items.map((pin: any) => ({
label: pin.title,
value: pin.id,
}));
return {
disabled: false,
options,
};
} catch (error) {
return {
disabled: true,
placeholder: 'Error loading pins. Please try again.',
options: [],
};
}
},
});

View File

@@ -0,0 +1,165 @@
import {
createTrigger,
TriggerStrategy,
PiecePropValueSchema,
Property,
OAuth2PropertyValue,
AppConnectionValueForAuthProperty,
} from '@activepieces/pieces-framework';
import {
DedupeStrategy,
Polling,
pollingHelper,
HttpMethod,
getAccessTokenOrThrow,
} from '@activepieces/pieces-common';
import dayjs from 'dayjs';
import { makeRequest } from '../common';
import { pinterestAuth } from '../common/auth';
import { adAccountIdDropdown } from '../common/props';
const polling: Polling<
AppConnectionValueForAuthProperty<typeof pinterestAuth>,
Record<string, any>
> = {
strategy: DedupeStrategy.TIMEBASED,
items: async ({ auth, propsValue, lastFetchEpochMS }) => {
const { ad_account_id, privacy_filter, page_size } = propsValue;
let bookmark: string | undefined = undefined;
let boards: any[] = [];
let pageCount = 0;
const maxPages = 10; // Limit to prevent excessive API calls
do {
pageCount++;
// Build query parameters
const searchParams = new URLSearchParams();
// Add page_size parameter
searchParams.append('page_size', (page_size || 25).toString());
if (bookmark) {
searchParams.append('bookmark', bookmark);
}
if (ad_account_id) {
searchParams.append('ad_account_id', ad_account_id);
}
if (privacy_filter && privacy_filter !== 'ALL') {
searchParams.append('privacy', privacy_filter);
}
const queryString = searchParams.toString();
const path = `/boards${queryString ? `?${queryString}` : ''}`;
try {
const response = await makeRequest(
getAccessTokenOrThrow(auth as OAuth2PropertyValue),
HttpMethod.GET,
path
);
const items = response.items || [];
boards = boards.concat(items);
bookmark = response.bookmark;
// Break early if we've found items older than last fetch
if (lastFetchEpochMS && items.length > 0) {
const hasNew = items.some(
(item: any) => dayjs(item.created_at).valueOf() > lastFetchEpochMS
);
if (!hasNew) break;
}
// Rate limiting awareness
if (bookmark && pageCount < maxPages) {
await new Promise((resolve) => setTimeout(resolve, 100));
}
} catch (error) {
console.error('Error fetching boards:', error);
break;
}
} while (bookmark && pageCount < maxPages);
// Filter by timestamp if this isn't the first run
if (lastFetchEpochMS) {
boards = boards.filter(
(item: any) => dayjs(item.created_at).valueOf() > lastFetchEpochMS
);
}
return boards.map((item) => ({
epochMilliSeconds: dayjs(item.created_at).valueOf(),
data: item,
}));
},
};
export const newBoard = createTrigger({
auth: pinterestAuth,
name: 'newBoard',
displayName: 'New Board',
description: 'Fires when a new board is created in the account.',
props: {
ad_account_id: adAccountIdDropdown,
privacy_filter: Property.StaticDropdown({
displayName: 'Board Privacy Filter',
required: false,
options: {
options: [
{ label: 'All Boards', value: 'ALL' },
{ label: 'Public Only', value: 'PUBLIC' },
{ label: 'Protected Only', value: 'PROTECTED' },
{ label: 'Secret Only', value: 'SECRET' },
{ label: 'Public and Secret', value: 'PUBLIC_AND_SECRET' },
],
},
description: 'Filter boards by privacy setting (optional).',
}),
page_size: Property.Number({
displayName: 'Page Size',
required: false,
description: 'Number of boards to fetch per page (1-250, default: 25).',
}),
},
sampleData: {
id: '549755885175',
created_at: '2020-01-01T20:10:40-00:00',
board_pins_modified_at: '2020-01-01T20:10:40-00:00',
name: 'Summer Recipes',
description: 'My favorite summer recipes',
collaborator_count: 17,
pin_count: 5,
follower_count: 13,
media: {
image_cover_url:
'https://i.pinimg.com/400x300/fd/cd/d5/fdcdd5a6d8a80824add0d054125cd957.jpg',
pin_thumbnail_urls: [
'https://i.pinimg.com/150x150/b4/57/10/b45710f1ede96af55230f4b43935c4af.jpg',
'https://i.pinimg.com/150x150/dd/ff/46/ddff4616e39c1935cd05738794fa860e.jpg',
'https://i.pinimg.com/150x150/84/ac/59/84ac59b670ccb5b903dace480a98930c.jpg',
'https://i.pinimg.com/150x150/4c/54/6f/4c546f521be85e30838fb742bfff6936.jpg',
],
},
owner: {
username: 'sample_username',
},
privacy: 'PUBLIC',
is_ads_only: false,
},
type: TriggerStrategy.POLLING,
async test(context) {
return await pollingHelper.test(polling, context);
},
async onEnable(context) {
const { store, auth, propsValue } = context;
await pollingHelper.onEnable(polling, { store, auth, propsValue });
},
async onDisable(context) {
const { store, auth, propsValue } = context;
await pollingHelper.onDisable(polling, { store, auth, propsValue });
},
async run(context) {
return await pollingHelper.poll(polling, context);
},
});

View File

@@ -0,0 +1,97 @@
import {
createTrigger,
TriggerStrategy,
PiecePropValueSchema,
OAuth2PropertyValue,
AppConnectionValueForAuthProperty,
} from '@activepieces/pieces-framework';
import {
DedupeStrategy,
Polling,
pollingHelper,
HttpMethod,
getAccessTokenOrThrow,
} from '@activepieces/pieces-common';
import { makeRequest } from '../common';
import { pinterestAuth } from '../common/auth';
const polling: Polling<
AppConnectionValueForAuthProperty<typeof pinterestAuth>,
Record<string, any>
> = {
strategy: DedupeStrategy.LAST_ITEM,
items: async ({ auth }) => {
let bookmark: string | undefined = undefined;
let followers: any[] = [];
let pageCount = 0;
const maxPages = 20; // Limit to prevent excessive API calls
do {
pageCount++;
// Build query parameters
const searchParams = new URLSearchParams();
if (bookmark) {
searchParams.append('bookmark', bookmark);
}
const queryString = searchParams.toString();
const path = `/user_account/followers${
queryString ? `?${queryString}` : ''
}`;
try {
const response = await makeRequest(
getAccessTokenOrThrow(auth as OAuth2PropertyValue),
HttpMethod.GET,
path
);
const items = response.items || [];
followers = followers.concat(items);
bookmark = response.bookmark;
// Rate limiting awareness - add delay between requests
if (bookmark && pageCount < maxPages) {
await new Promise((resolve) => setTimeout(resolve, 100));
}
} catch (error) {
console.error('Error fetching followers:', error);
break;
}
} while (bookmark && pageCount < maxPages);
// Return items with username as identifier
return followers.map((item) => ({
id: item.username,
data: item,
}));
},
};
export const newFollower = createTrigger({
auth: pinterestAuth,
name: 'newFollower',
displayName: 'New Follower',
description: 'Triggers when a user gains a new follower.',
props: {},
sampleData: {
username: 'sample_username',
type: 'user',
},
type: TriggerStrategy.POLLING,
async test(context) {
return await pollingHelper.test(polling, context);
},
async onEnable(context) {
const { store, auth, propsValue } = context;
await pollingHelper.onEnable(polling, { store, auth, propsValue });
},
async onDisable(context) {
const { store, auth, propsValue } = context;
await pollingHelper.onDisable(polling, { store, auth, propsValue });
},
async run(context) {
return await pollingHelper.poll(polling, context);
},
});

View File

@@ -0,0 +1,223 @@
import {
createTrigger,
TriggerStrategy,
PiecePropValueSchema,
Property,
OAuth2PropertyValue,
AppConnectionValueForAuthProperty,
} from '@activepieces/pieces-framework';
import {
DedupeStrategy,
Polling,
pollingHelper,
HttpMethod,
getAccessTokenOrThrow,
} from '@activepieces/pieces-common';
import dayjs from 'dayjs';
import { makeRequest } from '../common';
import { pinterestAuth } from '../common/auth';
import { adAccountIdDropdown, boardIdDropdown } from '../common/props';
const polling: Polling<
AppConnectionValueForAuthProperty<typeof pinterestAuth>,
Record<string, any>
> = {
strategy: DedupeStrategy.TIMEBASED,
items: async ({ propsValue, auth, lastFetchEpochMS }) => {
const { board_id, ad_account_id, creative_types } = propsValue;
let bookmark: string | undefined = undefined;
let pins: any[] = [];
let pageCount = 0;
const maxPages = 10; // Limit to prevent excessive API calls
const initialPageSize = 25; // Smaller initial page size for faster response
do {
pageCount++;
// Build query parameters
const searchParams = new URLSearchParams();
searchParams.append('page_size', initialPageSize.toString());
if (bookmark) {
searchParams.append('bookmark', bookmark);
}
if (ad_account_id) {
searchParams.append('ad_account_id', ad_account_id);
}
// Add creative_types filter if specified
if (creative_types && creative_types.length > 0) {
creative_types.forEach((type: string) => {
searchParams.append('creative_types', type);
});
}
const queryString = searchParams.toString();
const path = `/boards/${board_id}/pins${
queryString ? `?${queryString}` : ''
}`;
try {
const response = await makeRequest(
getAccessTokenOrThrow(auth as OAuth2PropertyValue),
HttpMethod.GET,
path
);
const items = response.items || [];
bookmark = response.bookmark;
// If this is not the first run, filter items by timestamp immediately
if (lastFetchEpochMS) {
const newItems = items.filter(
(item: any) => dayjs(item.created_at).valueOf() > lastFetchEpochMS
);
pins = pins.concat(newItems);
// Break early if no new items found in this page
if (newItems.length === 0) {
break;
}
// Break early if we found items older than last fetch
const hasOldItems = items.some(
(item: any) => dayjs(item.created_at).valueOf() <= lastFetchEpochMS
);
if (hasOldItems) {
break;
}
// Rate limiting awareness - add delay between requests
if (bookmark && pageCount < maxPages) {
await new Promise((resolve) => setTimeout(resolve, 100)); // 100ms delay
}
} else {
// First run - collect all items
pins = pins.concat(items);
}
} catch (error) {
console.error(`Error fetching pins for board ${board_id}:`, error);
break; // Stop pagination on error
}
} while (bookmark);
// Sort by creation date (newest first) for consistent ordering
pins.sort(
(a, b) => dayjs(b.created_at).valueOf() - dayjs(a.created_at).valueOf()
);
return pins.map((item) => ({
epochMilliSeconds: dayjs(item.created_at).valueOf(),
data: item,
}));
},
};
export const newPinOnBoard = createTrigger({
auth: pinterestAuth,
name: 'newPinOnBoard',
displayName: 'New Pin on Board',
description: 'Fires when a new Pin is added to a specific board.',
props: {
board_id: boardIdDropdown,
ad_account_id: adAccountIdDropdown,
creative_types: Property.StaticMultiSelectDropdown({
displayName: 'Pin Types to Watch',
required: false,
options: {
options: [
{ label: 'Regular Pins', value: 'REGULAR' },
{ label: 'Video Pins', value: 'VIDEO' },
{ label: 'Shopping Pins', value: 'SHOPPING' },
{ label: 'Carousel Pins', value: 'CAROUSEL' },
{ label: 'Idea Pins', value: 'IDEA' },
],
},
description:
'Filter by specific pin types. Leave empty to watch all types.',
}),
},
sampleData: {
items: [
{
id: '813744226420795884',
created_at: '2020-01-01T20:10:40-00:00',
link: 'https://www.pinterest.com/',
title: 'string',
description: 'string',
dominant_color: '#6E7874',
alt_text: 'string',
creative_type: 'REGULAR',
board_id: 'string',
board_section_id: 'string',
board_owner: {
username: 'string',
},
is_owner: 'false',
media: {
media_type: 'string',
images: {
'150x150': {
width: 150,
height: 150,
url: 'https://i.pinimg.com/150x150/0d/f6/f1/0df6f1f0bfe7aaca849c1bbc3607a34b.jpg',
},
'400x300': {
width: 400,
height: 300,
url: 'https://i.pinimg.com/400x300/0d/f6/f1/0df6f1f0bfe7aaca849c1bbc3607a34b.jpg',
},
'600x': {
width: 600,
height: 600,
url: 'https://i.pinimg.com/600x/0d/f6/f1/0df6f1f0bfe7aaca849c1bbc3607a34b.jpg',
},
'1200x': {
width: 1200,
height: 1200,
url: 'https://i.pinimg.com/1200x/0d/f6/f1/0df6f1f0bfe7aaca849c1bbc3607a34b.jpg',
},
},
},
parent_pin_id: 'string',
is_standard: 'false',
has_been_promoted: 'false',
product_tags: [
{
pin_id: '903972677830',
},
],
note: 'string',
pin_metrics: {
'90d': {
pin_click: 7,
impression: 2,
clickthrough: 3,
},
lifetime_metrics: {
pin_click: 7,
impression: 2,
clickthrough: 3,
reaction: 10,
comment: 2,
},
},
is_removable: true,
},
],
bookmark: 'string',
},
type: TriggerStrategy.POLLING,
async test(context) {
return await pollingHelper.test(polling, context);
},
async onEnable(context) {
const { store, auth, propsValue } = context;
await pollingHelper.onEnable(polling, { store, auth, propsValue });
},
async onDisable(context) {
const { store, auth, propsValue } = context;
await pollingHelper.onDisable(polling, { store, auth, propsValue });
},
async run(context) {
return await pollingHelper.poll(polling, context);
},
});

View File

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

View File

@@ -0,0 +1,11 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"module": "commonjs",
"outDir": "../../../../dist/out-tsc",
"declaration": true,
"types": ["node"]
},
"exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"],
"include": ["src/**/*.ts"]
}