diff --git a/independent-publisher-connectors/Guru/Readme.md b/independent-publisher-connectors/Guru/Readme.md new file mode 100644 index 0000000000..6c2092029c --- /dev/null +++ b/independent-publisher-connectors/Guru/Readme.md @@ -0,0 +1,80 @@ +# Guru + +Guru is a knowledge management platform that helps teams capture, organize, and share verified information. This connector enables you to search, create, update, and verify knowledge cards, browse collections and folders, and manage tag categories — all from within your automated workflows. + +## Publisher +### Aaron Mah + +## Prerequisites + +To use this connector, you need: + +1. A **Guru account** — sign up at [app.getguru.com](https://app.getguru.com). API access may require a paid plan (All-in-One at $15/user/month). See [Guru Pricing](https://www.getguru.com/pricing) for details. +2. A **User API Token**: + 1. Log into Guru at [app.getguru.com](https://app.getguru.com) + 2. Navigate to **Manage → Apps & Integrations → API Access** + 3. Click **Generate User Token** and give it a name + 4. Copy the token immediately — it cannot be viewed again +3. Your **Guru email address** (the one you use to log in) +4. In Power Automate, enter your Guru email as the **Username** and the API token as the **Password** + +Your API token inherits the permissions of your Guru user account. Most connector operations work with Author-level permissions or above. + +## Supported Operations + +### Search Cards +Search for cards using free-text terms and Guru Query Language filters. This is the primary way to list and find cards — Guru has no dedicated list endpoint. + +### Get Card +Retrieve a single card by ID with full content, verification state, and collection info. + +### Create Card +Create a new knowledge card in a collection with title, HTML content, and sharing options. + +### Update Card +Update an existing card's title, content, or sharing status. + +### Verify Card +Mark a card as verified (trusted), confirming its content is accurate and up-to-date. + +### Unverify Card +Remove verification from a card, marking it as needing review. + +### Archive Card +Archive (soft-delete) a card, removing it from active views. Archived cards can still be found with the Show Archived option in Search Cards. + +### List Collections +Get all knowledge collections accessible to the authenticated user. Useful for populating dropdowns when creating cards. + +### Get Collection +Get details of a specific knowledge collection by ID. + +### Get Folder +Retrieve details of a specific folder by ID. Folders are the organizational unit within collections. + +### Get Folder Items +List all cards and subfolders within a specific folder. + +### List Tag Categories +Get all tag categories and their tags for the team. Requires a Team ID. + +### List Card Versions +Get all historical versions of a card to track changes over time. + +## API Documentation + +Visit [Guru Developer Docs](https://developer.getguru.com/docs/getting-started) for further details on the API and its capabilities. + +## Known Issues and Limitations + +- **No card list endpoint** — Guru does not provide a `GET /cards` endpoint. Use the Search Cards operation to list and find cards. +- **Search pagination** — Search results are limited to 50 items per page. Use the `maxResults` parameter to control page size. Cursor-based pagination via `Link` headers is supported by the API but not exposed in this connector. +- **HTML content** — Card content (`content` field) is returned as HTML. Ensure your flow handles HTML formatting appropriately. +- **Rate limits** — Guru API rate limits are not publicly documented. If you encounter 429 errors, add delays between requests. +- **API token permissions** — Your token inherits your Guru user role. Admin operations (analytics, team management) require Admin-level access. +- **Archived cards** — The Archive Card operation performs a soft delete. Cards can be found again using Search Cards with `showArchived=true`. +- **Team ID required** — The List Tag Categories operation requires a Team ID parameter. You can obtain your Team ID from the Guru API by calling `GET /teams`. + +## License + +Distributed under the MIT License. diff --git a/independent-publisher-connectors/Guru/apiDefinition.swagger.json b/independent-publisher-connectors/Guru/apiDefinition.swagger.json new file mode 100644 index 0000000000..b6092b4b2b --- /dev/null +++ b/independent-publisher-connectors/Guru/apiDefinition.swagger.json @@ -0,0 +1,872 @@ +{ + "swagger": "2.0", + "info": { + "title": "Guru", + "description": "Guru is a knowledge management platform that helps teams capture, organize, and share verified information. Use this connector to search, create, update, and verify knowledge cards, browse collections and folders, and manage your team's knowledge base.", + "version": "1.0", + "contact": { + "name": "Aaron Mah", + "url": "https://github.com/aaronmah", + "email": "aaronmah@microsoft.com" + } + }, + "host": "api.getguru.com", + "basePath": "/api/v1", + "schemes": [ + "https" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": { + "/search/query": { + "get": { + "operationId": "searchCards", + "summary": "Search Cards", + "description": "Search for cards using free-text terms and Guru Query Language filters.", + "parameters": [ + { + "name": "searchTerms", + "in": "query", + "type": "string", + "required": false, + "description": "Free-text search across card title, content, and properties.", + "x-ms-summary": "Search Terms" + }, + { + "name": "q", + "in": "query", + "type": "string", + "required": false, + "description": "Guru Query Language filter string (e.g., lastModified < 7_days_ago).", + "x-ms-summary": "Query Filter" + }, + { + "name": "sortField", + "in": "query", + "type": "string", + "required": false, + "description": "Sort results by the specified field.", + "x-ms-summary": "Sort Field", + "enum": [ + "lastModified", + "dateCreated", + "title", + "viewCount", + "favoriteCount", + "verificationState", + "popularity" + ] + }, + { + "name": "sortOrder", + "in": "query", + "type": "string", + "required": false, + "description": "Sort order, either ascending or descending.", + "x-ms-summary": "Sort Order", + "enum": [ + "asc", + "desc" + ] + }, + { + "name": "maxResults", + "in": "query", + "type": "integer", + "required": false, + "description": "Maximum number of results per page (1-50). Default is 50.", + "x-ms-summary": "Max Results" + }, + { + "name": "showArchived", + "in": "query", + "type": "boolean", + "required": false, + "description": "Include archived cards in search results. Default is false.", + "x-ms-summary": "Show Archived" + } + ], + "responses": { + "200": { + "description": "A list of matching cards.", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/CardSummary" + } + } + } + } + } + }, + "/cards/{cardId}": { + "get": { + "operationId": "getCard", + "summary": "Get Card", + "description": "Retrieve a single card by ID with full content, verification state, and collection info.", + "parameters": [ + { + "name": "cardId", + "in": "path", + "type": "string", + "required": true, + "description": "The UUID of the card to retrieve.", + "x-ms-summary": "Card ID", + "x-ms-url-encoding": "single" + } + ], + "responses": { + "200": { + "description": "The card details.", + "schema": { + "$ref": "#/definitions/CardResponse" + } + } + } + }, + "put": { + "operationId": "updateCard", + "summary": "Update Card", + "description": "Update an existing card's title, content, or sharing status.", + "parameters": [ + { + "name": "cardId", + "in": "path", + "type": "string", + "required": true, + "description": "The UUID of the card to update.", + "x-ms-summary": "Card ID", + "x-ms-url-encoding": "single" + }, + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "type": "object", + "properties": { + "preferredPhrase": { + "type": "string", + "description": "Updated card title.", + "x-ms-summary": "Title" + }, + "content": { + "type": "string", + "description": "Updated HTML body content of the card.", + "x-ms-summary": "Content" + }, + "shareStatus": { + "type": "string", + "description": "Updated sharing level for the card.", + "x-ms-summary": "Share Status", + "enum": [ + "TEAM", + "PRIVATE", + "PUBLIC" + ] + } + } + } + } + ], + "responses": { + "200": { + "description": "The updated card details.", + "schema": { + "$ref": "#/definitions/CardResponse" + } + } + } + }, + "delete": { + "operationId": "archiveCard", + "summary": "Archive Card", + "description": "Archive (soft-delete) a card, removing it from active views.", + "consumes": [], + "parameters": [ + { + "name": "cardId", + "in": "path", + "type": "string", + "required": true, + "description": "The UUID of the card to archive.", + "x-ms-summary": "Card ID", + "x-ms-url-encoding": "single" + } + ], + "responses": { + "200": { + "description": "The card has been archived successfully." + } + } + } + }, + "/cards/extended": { + "post": { + "operationId": "createCard", + "summary": "Create Card", + "description": "Create a new knowledge card in a collection with title, HTML content, and sharing options.", + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "preferredPhrase", + "content", + "collection" + ], + "properties": { + "preferredPhrase": { + "type": "string", + "description": "The title of the card.", + "x-ms-summary": "Title" + }, + "content": { + "type": "string", + "description": "HTML body content of the card.", + "x-ms-summary": "Content" + }, + "collection": { + "type": "object", + "description": "The collection to create the card in.", + "required": [ + "id" + ], + "properties": { + "id": { + "type": "string", + "description": "UUID of the collection to create the card in.", + "x-ms-summary": "Collection ID", + "x-ms-dynamic-values": { + "operationId": "listCollections", + "value-path": "id", + "value-title": "name" + } + } + } + }, + "shareStatus": { + "type": "string", + "description": "Sharing level for the card. Default is TEAM.", + "x-ms-summary": "Share Status", + "enum": [ + "TEAM", + "PRIVATE", + "PUBLIC" + ], + "default": "TEAM" + } + } + } + } + ], + "responses": { + "200": { + "description": "The created card details.", + "schema": { + "$ref": "#/definitions/CardResponse" + } + } + } + } + }, + "/cards/{cardId}/verify": { + "put": { + "operationId": "verifyCard", + "summary": "Verify Card", + "description": "Mark a card as verified (trusted), confirming its content is accurate and up-to-date.", + "parameters": [ + { + "name": "cardId", + "in": "path", + "type": "string", + "required": true, + "description": "The UUID of the card to verify.", + "x-ms-summary": "Card ID", + "x-ms-url-encoding": "single" + } + ], + "responses": { + "200": { + "description": "Card verified successfully." + }, + "204": { + "description": "Card verified successfully. No content returned." + } + } + } + }, + "/cards/{cardId}/unverify": { + "post": { + "operationId": "unverifyCard", + "summary": "Unverify Card", + "description": "Remove verification from a card, marking it as needing review.", + "parameters": [ + { + "name": "cardId", + "in": "path", + "type": "string", + "required": true, + "description": "The UUID of the card to unverify.", + "x-ms-summary": "Card ID", + "x-ms-url-encoding": "single" + } + ], + "responses": { + "200": { + "description": "The card with updated verification details.", + "schema": { + "$ref": "#/definitions/CardResponse" + } + } + } + } + }, + "/cards/{cardId}/versions": { + "get": { + "operationId": "listCardVersions", + "summary": "List Card Versions", + "description": "Get all historical versions of a card to track changes over time.", + "parameters": [ + { + "name": "cardId", + "in": "path", + "type": "string", + "required": true, + "description": "The UUID of the card.", + "x-ms-summary": "Card ID", + "x-ms-url-encoding": "single" + } + ], + "responses": { + "200": { + "description": "A list of card versions.", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/CardVersion" + } + } + } + } + } + }, + "/collections": { + "get": { + "operationId": "listCollections", + "summary": "List Collections", + "description": "Get all knowledge collections accessible to the authenticated user.", + "parameters": [], + "responses": { + "200": { + "description": "A list of collections.", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/CollectionResponse" + } + } + } + } + } + }, + "/collections/{collectionId}": { + "get": { + "operationId": "getCollection", + "summary": "Get Collection", + "description": "Get details of a specific knowledge collection by ID.", + "parameters": [ + { + "name": "collectionId", + "in": "path", + "type": "string", + "required": true, + "description": "The UUID of the collection.", + "x-ms-summary": "Collection ID", + "x-ms-url-encoding": "single" + } + ], + "responses": { + "200": { + "description": "The collection details.", + "schema": { + "$ref": "#/definitions/CollectionResponse" + } + } + } + } + }, + "/folders/{folderId}": { + "get": { + "operationId": "getFolder", + "summary": "Get Folder", + "description": "Retrieve details of a specific folder by ID.", + "parameters": [ + { + "name": "folderId", + "in": "path", + "type": "string", + "required": true, + "description": "The UUID of the folder.", + "x-ms-summary": "Folder ID", + "x-ms-url-encoding": "single" + } + ], + "responses": { + "200": { + "description": "The folder details.", + "schema": { + "$ref": "#/definitions/FolderResponse" + } + } + } + } + }, + "/folders/{folderId}/items": { + "get": { + "operationId": "getFolderItems", + "summary": "Get Folder Items", + "description": "List all cards and subfolders within a specific folder.", + "parameters": [ + { + "name": "folderId", + "in": "path", + "type": "string", + "required": true, + "description": "The UUID of the folder.", + "x-ms-summary": "Folder ID", + "x-ms-url-encoding": "single" + } + ], + "responses": { + "200": { + "description": "A list of folder items (cards and subfolders).", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/FolderItem" + } + } + } + } + } + }, + "/teams/{teamId}/tagcategories": { + "get": { + "operationId": "listTagCategories", + "summary": "List Tag Categories", + "description": "Get all tag categories and their tags for the team.", + "parameters": [ + { + "name": "teamId", + "in": "path", + "type": "string", + "required": true, + "description": "The UUID of the team.", + "x-ms-summary": "Team ID", + "x-ms-url-encoding": "single" + } + ], + "responses": { + "200": { + "description": "A list of tag categories with their tags.", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/TagCategory" + } + } + } + } + } + } + }, + "definitions": { + "CardResponse": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The unique identifier of the card.", + "title": "Card ID" + }, + "version": { + "type": "integer", + "format": "int32", + "description": "The current version number of the card.", + "title": "Version" + }, + "preferredPhrase": { + "type": "string", + "description": "The title of the card.", + "title": "Title" + }, + "content": { + "type": "string", + "description": "The HTML body content of the card.", + "title": "Content" + }, + "verificationState": { + "type": "string", + "description": "The verification state of the card (TRUSTED, NEEDS_VERIFICATION, or UNVERIFIED).", + "title": "Verification State" + }, + "lastModified": { + "type": "string", + "description": "The ISO-8601 timestamp of last modification.", + "title": "Last Modified" + }, + "dateCreated": { + "type": "string", + "description": "The ISO-8601 timestamp of creation.", + "title": "Date Created" + }, + "collection": { + "type": "object", + "description": "The collection containing this card.", + "properties": { + "id": { + "type": "string", + "description": "The collection UUID.", + "title": "Collection ID" + }, + "name": { + "type": "string", + "description": "The collection name.", + "title": "Collection Name" + } + } + }, + "shareStatus": { + "type": "string", + "description": "The sharing level of the card (TEAM, PRIVATE, or PUBLIC).", + "title": "Share Status" + }, + "slug": { + "type": "string", + "description": "The URL slug for the card.", + "title": "Slug" + }, + "owner": { + "type": "object", + "description": "The owner of the card.", + "properties": { + "email": { + "type": "string", + "description": "The email address of the card owner.", + "title": "Owner Email" + } + } + }, + "lastVerified": { + "type": "string", + "description": "The ISO-8601 timestamp of last verification.", + "title": "Last Verified" + }, + "nextVerificationDate": { + "type": "string", + "description": "The ISO-8601 timestamp of next required verification.", + "title": "Next Verification Date" + } + } + }, + "CardSummary": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The unique identifier of the card.", + "title": "Card ID" + }, + "version": { + "type": "integer", + "format": "int32", + "description": "The current version number of the card.", + "title": "Version" + }, + "preferredPhrase": { + "type": "string", + "description": "The title of the card.", + "title": "Title" + }, + "content": { + "type": "string", + "description": "The HTML body content of the card.", + "title": "Content" + }, + "verificationState": { + "type": "string", + "description": "The verification state of the card.", + "title": "Verification State" + }, + "lastModified": { + "type": "string", + "description": "The ISO-8601 timestamp of last modification.", + "title": "Last Modified" + }, + "dateCreated": { + "type": "string", + "description": "The ISO-8601 timestamp of creation.", + "title": "Date Created" + }, + "collection": { + "type": "object", + "description": "The collection containing this card.", + "properties": { + "id": { + "type": "string", + "description": "The collection UUID.", + "title": "Collection ID" + }, + "name": { + "type": "string", + "description": "The collection name.", + "title": "Collection Name" + } + } + }, + "shareStatus": { + "type": "string", + "description": "The sharing level of the card.", + "title": "Share Status" + }, + "slug": { + "type": "string", + "description": "The URL slug for the card.", + "title": "Slug" + } + } + }, + "CollectionResponse": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The unique identifier of the collection.", + "title": "Collection ID" + }, + "name": { + "type": "string", + "description": "The name of the collection.", + "title": "Name" + }, + "description": { + "type": "string", + "description": "The description of the collection.", + "title": "Description" + }, + "color": { + "type": "string", + "description": "The color code of the collection.", + "title": "Color" + }, + "collectionType": { + "type": "string", + "description": "The type of collection (e.g., INTERNAL).", + "title": "Collection Type" + }, + "publicCardsEnabled": { + "type": "boolean", + "description": "Whether public cards are enabled in this collection.", + "title": "Public Cards Enabled" + }, + "slug": { + "type": "string", + "description": "The URL slug for the collection.", + "title": "Slug" + } + } + }, + "FolderResponse": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The unique identifier of the folder.", + "title": "Folder ID" + }, + "title": { + "type": "string", + "description": "The name of the folder.", + "title": "Title" + }, + "slug": { + "type": "string", + "description": "The URL slug for the folder.", + "title": "Slug" + }, + "itemCount": { + "type": "integer", + "format": "int32", + "description": "The number of items in the folder.", + "title": "Item Count" + }, + "collection": { + "type": "object", + "description": "The parent collection.", + "properties": { + "id": { + "type": "string", + "description": "The parent collection UUID.", + "title": "Collection ID" + }, + "name": { + "type": "string", + "description": "The parent collection name.", + "title": "Collection Name" + } + } + } + } + }, + "FolderItem": { + "type": "object", + "properties": { + "type": { + "type": "string", + "description": "The type of item (card or folder).", + "title": "Type" + }, + "itemId": { + "type": "string", + "description": "The unique identifier of the item.", + "title": "Item ID" + }, + "id": { + "type": "string", + "description": "The card or folder UUID.", + "title": "ID" + }, + "preferredPhrase": { + "type": "string", + "description": "The card title (for card items).", + "title": "Card Title" + }, + "title": { + "type": "string", + "description": "The folder name (for folder items).", + "title": "Folder Title" + }, + "shareStatus": { + "type": "string", + "description": "The sharing level (for card items).", + "title": "Share Status" + }, + "verificationState": { + "type": "string", + "description": "The verification state (for card items).", + "title": "Verification State" + }, + "slug": { + "type": "string", + "description": "The URL slug (for card items).", + "title": "Slug" + } + } + }, + "TagCategory": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The unique identifier of the tag category.", + "title": "Category ID" + }, + "name": { + "type": "string", + "description": "The name of the tag category.", + "title": "Category Name" + }, + "tags": { + "type": "array", + "description": "The tags in this category.", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The tag UUID.", + "title": "Tag ID" + }, + "value": { + "type": "string", + "description": "The tag display name.", + "title": "Tag Value" + }, + "categoryName": { + "type": "string", + "description": "The parent category name.", + "title": "Category Name" + } + } + } + } + } + }, + "CardVersion": { + "type": "object", + "properties": { + "version": { + "type": "integer", + "format": "int32", + "description": "The version number.", + "title": "Version" + }, + "content": { + "type": "string", + "description": "The HTML content at this version.", + "title": "Content" + }, + "preferredPhrase": { + "type": "string", + "description": "The card title at this version.", + "title": "Title" + }, + "lastModified": { + "type": "string", + "description": "The ISO-8601 timestamp of this version.", + "title": "Last Modified" + }, + "saveType": { + "type": "string", + "description": "The type of save (e.g., USER, IMPORT).", + "title": "Save Type" + } + } + } + }, + "parameters": {}, + "responses": {}, + "securityDefinitions": { + "basic-auth": { + "type": "basic" + } + }, + "security": [ + { + "basic-auth": [] + } + ], + "tags": [], + "x-ms-connector-metadata": [ + { + "propertyName": "Website", + "propertyValue": "https://www.getguru.com" + }, + { + "propertyName": "Privacy policy", + "propertyValue": "https://www.getguru.com/privacy-policy" + }, + { + "propertyName": "Categories", + "propertyValue": "Collaboration;Productivity" + } + ] +} diff --git a/independent-publisher-connectors/Guru/apiProperties.json b/independent-publisher-connectors/Guru/apiProperties.json new file mode 100644 index 0000000000..ce64cfce80 --- /dev/null +++ b/independent-publisher-connectors/Guru/apiProperties.json @@ -0,0 +1,36 @@ +{ + "properties": { + "connectionParameters": { + "username": { + "type": "securestring", + "uiDefinition": { + "displayName": "Email", + "description": "Your Guru account email address.", + "tooltip": "Enter your Guru login email address.", + "constraints": { + "tabIndex": 2, + "clearText": true, + "required": "true" + } + } + }, + "password": { + "type": "securestring", + "uiDefinition": { + "displayName": "API Token", + "description": "Your Guru API token.", + "tooltip": "Go to Guru → Manage → Apps & Integrations → API Access to generate a token.", + "constraints": { + "tabIndex": 3, + "clearText": false, + "required": "true" + } + } + } + }, + "iconBrandColor": "#da3b01", + "capabilities": [], + "publisher": "Aaron Mah", + "stackOwner": "Guru Technologies, Inc." + } +}