{ "kind": "open-flow-workflow", "version": 1, "name": "Add GitHub Pull Requests to Pipedrive Contacts", "content": { "modelVersion": 14, "document": { "bindings": {}, "graph": { "nodes": { "n_ffd56b9aa18eedb5": { "name": "Receive pull request events", "kind": "integration", "config": { "owner": { "kind": "value", "value": "your-github-owner" }, "repo": { "kind": "value", "value": "your-github-repo" }, "events": { "kind": "value", "value": [ "pull_request" ] }, "insecureSsl": { "kind": "value", "value": false } }, "definition": { "configInputs": [ { "jsonSchema": { "type": "array", "items": { "type": "string", "enum": [ "*", "branch_protection_configuration", "branch_protection_rule", "check_run", "check_suite", "code_scanning_alert", "commit_comment", "create", "custom_property_values", "delete", "dependabot_alert", "deploy_key", "deployment", "deployment_status", "discussion", "discussion_comment", "fork", "gollum", "issue_comment", "issue_dependencies", "issues", "label", "member", "meta", "milestone", "package", "page_build", "project", "project_card", "project_column", "public", "pull_request", "pull_request_review", "pull_request_review_comment", "pull_request_review_thread", "push", "registry_package", "release", "repository", "repository_advisory", "repository_import", "repository_ruleset", "repository_vulnerability_alert", "secret_scanning_alert", "secret_scanning_alert_location", "secret_scanning_scan", "security_and_analysis", "star", "status", "sub_issues", "team_add", "watch", "workflow_job", "workflow_run" ] }, "minItems": 1, "uniqueItems": true }, "nullable": false, "handle": "events" }, { "jsonSchema": { "type": "boolean" }, "nullable": false, "handle": "insecureSsl", "value": false }, { "jsonSchema": { "type": "string", "pattern": "^[a-zA-Z0-9](?:[a-zA-Z0-9]|-(?=[a-zA-Z0-9])){0,38}$" }, "nullable": false, "handle": "owner" }, { "jsonSchema": { "type": "string", "pattern": "^(?!\\.{1,2}$)[a-zA-Z0-9._-]{1,100}$" }, "nullable": false, "handle": "repo" } ], "definitionVersion": 2, "description": "Triggers when selected GitHub webhook events occur in a repository.", "displayName": "Repository Event", "key": "github.on_repo_event", "name": "on_repo_event", "outputs": [ { "jsonSchema": { "type": "object" }, "nullable": false, "handle": "body" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "deliveryId" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "event" } ], "provider": "github", "type": "integration", "endpoint": { "body": { "allowArray": false, "allowEmpty": false, "formats": [ "json" ] }, "methods": [ "POST" ], "successStatus": 202 } } }, "n_0ee8ab333d7a0d7d": { "inputs": { "body": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_ffd56b9aa18eedb5", "output": "body" } ] } }, "name": "Read the sender and pull request", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "object", "additionalProperties": true }, "nullable": false, "handle": "body" } ], "outputs": [ { "jsonSchema": { "type": "string", "minLength": 1 }, "nullable": false, "handle": "login" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "url" } ], "name": "Read the sender and pull request", "moduleId": "n_345dd6f6a558cc12", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [] } ] } }, "n_25ee43a1ae6d94e0": { "inputs": { "username": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_0ee8ab333d7a0d7d", "output": "login" } ] } }, "name": "Get the sender profile", "kind": "task", "task": { "inputs": [ { "description": "The username.", "jsonSchema": { "type": "string", "minLength": 1, "description": "The username." }, "nullable": false, "handle": "username" } ], "outputs": [ { "description": "A GitHub user profile.", "jsonSchema": { "allOf": [ { "type": "object", "properties": { "id": { "type": "integer", "description": "The user ID." }, "login": { "type": "string", "description": "The username." }, "avatar_url": { "type": "string", "description": "The avatar URL." }, "html_url": { "type": "string", "description": "The profile URL." }, "type": { "type": "string", "description": "The account type." } }, "required": [ "id", "login" ], "additionalProperties": true, "description": "A GitHub user summary." }, { "type": "object", "properties": { "name": { "type": [ "string", "null" ], "description": "The display name." }, "email": { "type": [ "string", "null" ], "description": "The email address." }, "bio": { "type": [ "string", "null" ], "description": "The bio." }, "company": { "type": [ "string", "null" ], "description": "The company." }, "location": { "type": [ "string", "null" ], "description": "The location." }, "followers": { "type": "integer", "description": "The number of followers." }, "following": { "type": "integer", "description": "The number of users followed." }, "public_repos": { "type": "integer", "description": "The number of public repositories." } }, "additionalProperties": true, "description": "Additional object fields." } ], "description": "A GitHub user profile." }, "nullable": false, "handle": "output" } ], "name": "Get the sender profile", "executor": { "kind": "connector", "action": "github.get_user", "outputMode": "value" } } }, "n_6b7aaeb460d20427": { "inputs": { "user": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_25ee43a1ae6d94e0", "output": "output" } ] } }, "name": "Check the public email", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "allOf": [ { "type": "object", "properties": { "id": { "type": "integer", "description": "The user ID." }, "login": { "type": "string", "description": "The username." }, "avatar_url": { "type": "string", "description": "The avatar URL." }, "html_url": { "type": "string", "description": "The profile URL." }, "type": { "type": "string", "description": "The account type." } }, "required": [ "id", "login" ], "additionalProperties": true, "description": "A GitHub user summary." }, { "type": "object", "properties": { "name": { "type": [ "string", "null" ], "description": "The display name." }, "email": { "type": [ "string", "null" ], "description": "The email address." }, "bio": { "type": [ "string", "null" ], "description": "The bio." }, "company": { "type": [ "string", "null" ], "description": "The company." }, "location": { "type": [ "string", "null" ], "description": "The location." }, "followers": { "type": "integer", "description": "The number of followers." }, "following": { "type": "integer", "description": "The number of users followed." }, "public_repos": { "type": "integer", "description": "The number of public repositories." } }, "additionalProperties": true, "description": "Additional object fields." } ], "description": "A GitHub user profile." }, "nullable": false, "handle": "user" } ], "outputs": [ { "jsonSchema": { "type": "boolean" }, "nullable": false, "handle": "available" }, { "jsonSchema": { "type": "string", "minLength": 1 }, "nullable": false, "handle": "email" } ], "name": "Check the public email", "moduleId": "n_7f7596b524af7f46", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [] } ] } }, "n_d1c0ae58e033c41b": { "inputs": {}, "name": "Public email available", "kind": "condition", "matchMode": "first", "cases": [ { "output": "yes", "groups": [ { "expressions": [ { "left": { "kind": "source", "source": { "kind": "node", "nodeId": "n_6b7aaeb460d20427", "output": "available" } }, "operator": "==", "right": { "kind": "value", "value": true } } ] } ] } ] }, "n_3d3f370b0d7e0a97": { "inputs": { "term": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_6b7aaeb460d20427", "output": "email" } ] }, "fields": { "kind": "value", "value": [ "email" ] }, "exactMatch": { "kind": "value", "value": true }, "limit": { "kind": "value", "value": 100 } }, "name": "Search people by email", "kind": "task", "task": { "inputs": [ { "description": "Search term to send to Pipedrive. Use at least 2 characters unless exactMatch is true.", "jsonSchema": { "type": "string", "minLength": 1, "description": "Search term to send to Pipedrive. Use at least 2 characters unless exactMatch is true." }, "nullable": false, "handle": "term" }, { "description": "Person fields to search through.", "jsonSchema": { "type": "array", "items": { "type": "string", "enum": [ "custom_fields", "email", "notes", "phone", "name" ], "description": "Person search field accepted by Pipedrive." }, "minItems": 1, "description": "Person fields to search through." }, "nullable": true, "handle": "fields", "value": null }, { "description": "Whether Pipedrive should only return case-insensitive exact matches.", "jsonSchema": { "type": "boolean", "description": "Whether Pipedrive should only return case-insensitive exact matches." }, "nullable": true, "handle": "exactMatch", "value": null }, { "description": "Organization ID filter.", "jsonSchema": { "type": "integer", "exclusiveMinimum": 0, "description": "Organization ID filter." }, "nullable": true, "handle": "organizationId", "value": null }, { "description": "Optional fields to include in search results.", "jsonSchema": { "type": "array", "items": { "type": "string", "enum": [ "person.picture" ], "description": "Optional person search field accepted by Pipedrive." }, "minItems": 1, "description": "Optional fields to include in search results." }, "nullable": true, "handle": "includeFields", "value": null }, { "description": "Maximum number of search results to return in one Pipedrive page.", "jsonSchema": { "type": "integer", "minimum": 1, "maximum": 500, "description": "Maximum number of search results to return in one Pipedrive page." }, "nullable": true, "handle": "limit", "value": null }, { "description": "Opaque pagination cursor returned by a previous Pipedrive response.", "jsonSchema": { "type": "string", "minLength": 1, "description": "Opaque pagination cursor returned by a previous Pipedrive response." }, "nullable": true, "handle": "cursor", "value": null } ], "outputs": [ { "description": "Search results returned by Pipedrive for person.", "jsonSchema": { "type": "array", "items": { "type": "object", "properties": { "result_score": { "type": "number", "description": "Search relevance score." }, "item": { "type": "object", "properties": { "id": { "type": "integer", "exclusiveMinimum": 0, "description": "Person ID." }, "type": { "type": "string", "description": "Search item type." }, "name": { "type": "string", "description": "Person name." }, "phones": { "type": "array", "items": { "type": "string", "description": "Matched phone number." }, "description": "Phone numbers included in the search hit." }, "emails": { "type": "array", "items": { "type": "string", "description": "Matched email address." }, "description": "Email addresses included in the search hit." }, "visible_to": { "type": "integer", "description": "Pipedrive visibility flag." }, "owner": { "type": "object", "properties": { "id": { "type": "integer", "exclusiveMinimum": 0, "description": "Owner user ID." } }, "required": [ "id" ], "additionalProperties": true, "description": "Owner reference." }, "organization": { "type": "object", "properties": { "id": { "type": "integer", "exclusiveMinimum": 0, "description": "Organization ID." }, "name": { "type": "string", "description": "Organization name." }, "address": { "type": [ "string", "null" ], "description": "Organization address." } }, "required": [ "id", "name" ], "additionalProperties": true, "description": "Related organization reference." }, "custom_fields": { "type": "array", "items": { "type": "string", "description": "Matched custom field value." }, "description": "Matched custom field values." }, "notes": { "type": "array", "items": { "type": "string", "description": "Matched note snippet." }, "description": "Matched notes." } }, "required": [ "id", "type", "name" ], "additionalProperties": true, "description": "Matched Pipedrive person." } }, "required": [ "result_score", "item" ], "additionalProperties": false, "description": "Pipedrive person search result." }, "description": "Search results returned by Pipedrive for person." }, "nullable": false, "handle": "items" }, { "description": "Cursor for the next page when Pipedrive has more search results.", "jsonSchema": { "type": [ "string", "null" ], "description": "Cursor for the next page when Pipedrive has more search results." }, "nullable": true, "handle": "nextCursor" } ], "name": "Search people by email", "executor": { "kind": "connector", "action": "pipedrive.search_persons" } } }, "n_67292063a809330d": { "inputs": { "items": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_3d3f370b0d7e0a97", "output": "items" } ] }, "url": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_0ee8ab333d7a0d7d", "output": "url" } ] }, "previousState": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_67292063a809330d", "output": "state" } ] } }, "name": "Prepare the next note", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "nullable": false, "handle": "items" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "url" }, { "jsonSchema": { "type": "object", "additionalProperties": true }, "nullable": true, "handle": "previousState" } ], "outputs": [ { "jsonSchema": { "type": "boolean" }, "nullable": false, "handle": "more" }, { "jsonSchema": { "type": "object", "additionalProperties": true }, "nullable": false, "handle": "state" }, { "jsonSchema": { "type": "object", "additionalProperties": true }, "nullable": false, "handle": "body" } ], "name": "Prepare the next note", "moduleId": "n_36d033a268fdbb79", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [] } ] } }, "n_d70f45f252167f89": { "inputs": {}, "name": "Another matching person", "kind": "condition", "matchMode": "first", "cases": [ { "output": "yes", "groups": [ { "expressions": [ { "left": { "kind": "source", "source": { "kind": "node", "nodeId": "n_67292063a809330d", "output": "more" } }, "operator": "==", "right": { "kind": "value", "value": true } } ] } ] } ] }, "n_209240e21dc1730c": { "inputs": { "endpoint": { "kind": "value", "value": "/api/v1/notes" }, "body": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_67292063a809330d", "output": "body" } ] } }, "name": "Add a Pipedrive note", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "endpoint" }, { "jsonSchema": {}, "nullable": true, "handle": "body" } ], "outputs": [ { "jsonSchema": {}, "nullable": true, "handle": "body" }, { "jsonSchema": { "type": "integer" }, "nullable": false, "handle": "statusCode" }, { "jsonSchema": { "type": "object", "additionalProperties": { "type": "string" } }, "nullable": false, "handle": "headers" }, { "jsonSchema": { "const": "base64" }, "nullable": true, "handle": "bodyEncoding" } ], "name": "Add a Pipedrive note", "executor": { "providerId": "pipedrive", "method": "POST", "query": { "mode": "fields", "names": [] }, "headers": { "mode": "fields", "names": [] }, "bodyFormat": "json", "kind": "connector-proxy" } } }, "n_eacff70f6028be51": { "inputs": { "statusCode": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_209240e21dc1730c", "output": "statusCode" } ] }, "body": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_209240e21dc1730c", "output": "body" } ] } }, "name": "Check the note result", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "integer" }, "nullable": false, "handle": "statusCode" }, { "jsonSchema": {}, "nullable": true, "handle": "body" } ], "outputs": [], "name": "Check the note result", "moduleId": "n_f6fa16e5ce475ec8", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [] } ] } } }, "edges": [ { "source": "n_ffd56b9aa18eedb5", "target": "n_0ee8ab333d7a0d7d" }, { "source": "n_0ee8ab333d7a0d7d", "target": "n_25ee43a1ae6d94e0" }, { "source": "n_25ee43a1ae6d94e0", "target": "n_6b7aaeb460d20427" }, { "source": "n_6b7aaeb460d20427", "target": "n_d1c0ae58e033c41b" }, { "source": "n_d1c0ae58e033c41b", "target": "n_3d3f370b0d7e0a97", "sourceHandle": "yes" }, { "source": "n_3d3f370b0d7e0a97", "target": "n_67292063a809330d" }, { "source": "n_67292063a809330d", "target": "n_d70f45f252167f89" }, { "source": "n_d70f45f252167f89", "target": "n_209240e21dc1730c", "sourceHandle": "yes" }, { "source": "n_209240e21dc1730c", "target": "n_eacff70f6028be51" }, { "source": "n_eacff70f6028be51", "target": "n_67292063a809330d" } ] } }, "modules": { "n_345dd6f6a558cc12": { "name": "Read the sender and pull request", "imports": [], "source": "export default function event({body}) {\n const login=body?.sender?.login, url=body?.pull_request?.html_url;\n if(typeof login!=='string'||!login.trim()||typeof url!=='string') throw Error('Pull request event is missing its sender or URL');\n const parsed=new URL(url); if(parsed.protocol!=='https:'||parsed.hostname!=='github.com'||parsed.username||parsed.password) throw Error('Invalid GitHub pull request URL');\n return {login,url};\n}\n" }, "n_7f7596b524af7f46": { "name": "Check the public email", "imports": [], "source": "export default function email({user}) {\n const value=user?.email;\n if(value==null||value==='')return {available:false,email:'-' };\n if(typeof value!=='string'||!value.trim())throw Error('Invalid public email');\n return {available:true,email:value.trim()};\n}\n" }, "n_36d033a268fdbb79": { "name": "Prepare the next note", "imports": [], "source": "export default function next({items,url,previousState}) {\n if(!Array.isArray(items))throw Error('Invalid Pipedrive search results');\n let index=previousState?.index??0;\n if(!Number.isSafeInteger(index)||index<0||index>items.length)throw Error('Invalid iteration state');\n while(index','>').replaceAll('\"','"').replaceAll(\"'\",''');\n return {more:true,state:{index},body:{person_id:person.id,content:'Created a PR \\n'+safe}};\n }\n return {more:false,state:{index},body:{}};\n}\n" }, "n_f6fa16e5ce475ec8": { "name": "Check the note result", "imports": [], "source": "export default function({statusCode,body}){if(statusCode<200||statusCode>=300||!body||body.success!==true)throw Error(\"Pipedrive note creation failed\");return {};} " } } }, "presentation": { "designer": { "version": 1, "flow": { "direction": "vertical" } } } }