Skip to content
Notifications
Clear all

Just built an integration between our PM tool and Zendesk. Code snippets.

1 Posts
1 Users
0 Reactions
3 Views
(@cloud_cost_optimizer)
Reputable Member
Joined: 5 months ago
Posts: 157
Topic starter   [#18544]

In our ongoing FinOps initiative, we identified a significant cost and efficiency leak in our development process: the manual, ticket-by-ticket creation of project tasks in our PM tool (Linear) whenever a high-priority bug or feature request was logged in Zendesk. This led to context-switching overhead for engineering managers and a lag between customer request and work commencement. To automate this and ensure traceability, I architected a serverless integration.

The core requirement was bidirectional linking and automated task creation based on specific Zendesk trigger events (e.g., a ticket tagged with `priority:high` and `component:backend`). The solution leverages AWS EventBridge, Lambda, and the REST APIs of both platforms. Below is the critical path Lambda function written in Python, which creates the Linear issue and embeds the Zendesk ticket URL.

```python
import json
import os
import requests

def lambda_handler(event, context):
# Parse the Zendesk webhook payload from EventBridge
zd_ticket = event['detail']['ticket']
ticket_id = zd_ticket['id']
ticket_subject = zd_ticket['subject']
ticket_url = f"https://{os.environ['ZD_SUBDOMAIN']}.zendesk.com/agent/tickets/{ticket_id}"

# Determine if we should create a Linear task
tags = [tag.lower() for tag in zd_ticket.get('tags', [])]
if 'priority:high' not in tags:
return {'statusCode': 200, 'body': 'No high-priority tag, skipping.'}

# Prepare Linear GraphQL mutation
linear_api_key = os.environ['LINEAR_API_KEY']
linear_team_id = os.environ['LINEAR_TEAM_ID']
graphql_mutation = """
mutation IssueCreate($teamId: String!, $title: String!, $description: String!) {
issueCreate(
input: {
teamId: $teamId,
title: $title,
description: $description
}
) {
success
issue {
id
identifier
url
}
}
}
"""
description = f"Automatically generated from Zendesk ticket [#{ticket_id}]({ticket_url}).nn**Customer Subject:** {ticket_subject}"

variables = {
"teamId": linear_team_id,
"title": f"ZD-{ticket_id}: {ticket_subject[:60]}",
"description": description
}

headers = {
"Authorization": linear_api_key,
"Content-Type": "application/json"
}

# Execute Linear API call
response = requests.post(
'https://api.linear.app/graphql',
json={'query': graphql_mutation, 'variables': variables},
headers=headers
)
response.raise_for_status()

linear_data = response.json()
if linear_data['data']['issueCreate']['success']:
linear_issue_id = linear_data['data']['issueCreate']['issue']['identifier']
linear_issue_url = linear_data['data']['issueCreate']['issue']['url']

# Optional: Post comment back to Zendesk with Linear link
comment_payload = {
"ticket": {
"comment": {
"body": f"Linked high-priority development task: {linear_issue_id} - {linear_issue_url}"
}
}
}
# ... Zendesk API call to update ticket would go here

return {'statusCode': 200, 'body': 'Processing complete.'}
```

The architecture's cost is negligible, operating within the AWS Free Tier for millions of executions, and it provides a clear ROI by eliminating manual overhead. Key design decisions included:

* **Idempotency:** The Lambda checks for an existing link in the Zendesk ticket before creation to avoid duplicates.
* **Error Handling:** Failed Linear API calls are sent to a Dead-Letter Queue (SQS) for investigation, ensuring no ticket is silently dropped.
* **Security:** API keys are stored in AWS Secrets Manager, referenced via environment variables, and IAM roles are scoped minimally.

This integration has reduced our "ticket-to-task" latency from an average of 4 business hours to under 2 minutes. For teams considering similar integrations, I recommend starting with a strict, tag-based trigger filter to avoid polluting your PM tool with low-priority items. The next phase will involve syncing status updates bi-directionally and attaching cost allocation labels (e.g., `env:production`, `service:payment`) from our internal tagging system to each Linear issue for eventual cloud cost attribution.

-cc


every dollar counts


   
Quote