All workflows

Flag churn risk in new support tickets for customer success

Reads new Zendesk tickets, scores churn risk and urgency with Jev, tags and prioritizes the risky ones, and alerts each owner in Slack.

Outcome

  • A table of every new ticket with its churn-risk level, issue type, urgency and Jev's confidence.

  • Each at-risk ticket tagged, reprioritized and given an internal note in Zendesk.

  • A Slack post for each at-risk ticket that mentions its HubSpot owner and carries a drafted check-in.

How it works

  1. 1

    Pull new tickets

    Zendesk

    Search for tickets (type:ticket) created after since, leaving out those already tagged risk_tag. Keep each ticket's ID, subject, description, priority, tags and requester ID.

  2. 2

    Read each ticket

    TypeSafe AI

    Send the subject and description as the state, with a score churn_risk on four levels (no risk; frustrated; weighing a downgrade or another tool; says they will cancel), a choice issue of bug, billing, how_to, missing_feature, performance, access, cancellation and other, a score urgency on three levels (can wait; this week; today), a noul mentions_competitor and a noul asks_for_refund. Keep every answer with its confidence or probability.

  3. 3

    Check the unsure ones with the user

    Your agent

    Show the user every ticket whose churn_risk confidence is below min_confidence, and keep the level the user picks. Keep the tickets whose most likely churn_risk level is risk_level or higher, and look up each one's requester email, a read-only call.

  4. 4

    Find the owner

    HubSpot

    Search companies by each at-risk requester's email domain, skipping free email domains. Keep the company's record ID, name and hubspot_owner_id, and look up each owner's name and email, a read-only call. Note the tickets with no match.

  5. 5

    Mark the ticket

    Zendesk

    After the user approves, add risk_tag alongside each at-risk ticket's existing tags, raise its priority to high, or urgent when its urgency is today, and add an internal note, not a public reply, with the churn-risk level, the issue and the competitor and refund probabilities.

  6. 6

    Draft the check-in

    Your agent

    Write a short note from each company's owner, by name, that names the problem in the ticket, says what happens next and offers a call, leaving a [fill in] for any fix date or commitment you don't have. Show the drafts to the user.

  7. 7

    Find the owners in Slack

    Slack

    Look up each owner's email. Keep their Slack user ID.

  8. 8

    Alert the owner

    Slack

    Post each at-risk ticket to cs_channel, mentioning its owner, with the company, the churn-risk level, the issue, the competitor and refund probabilities, the ticket ID and the drafted check-in.

You'll be asked for

  • When the last run started, as a time, so only newer tickets are read

    e.g. 2026-09-28T09:00:00Z

  • The lowest churn-risk level that counts as at risk

    e.g. weighing a downgrade or another tool

  • How sure Jev must be before its answer is used without you

    e.g. 0.8; a yes-or-no answer counts as yes at or above it and as no at or below 1 minus it

  • The Zendesk tag that marks an at-risk ticket

    e.g. churn_risk

  • The Slack channel customer success watches

    e.g. #cs-alerts

The file your agent runs

support-ticket-churn-risk.md

Flag churn risk in new support tickets for customer success

Reads new Zendesk tickets, scores churn risk and urgency with Jev, tags and prioritizes the risky ones, and alerts each owner in Slack.

Set up the tools below, then run the steps in order for the user, carrying each step's results into the next. The run is done when the user has the outcome below.

Outcome

  • A table of every new ticket with its churn-risk level, issue type, urgency and Jev's confidence.
  • Each at-risk ticket tagged, reprioritized and given an internal note in Zendesk.
  • A Slack post for each at-risk ticket that mentions its HubSpot owner and carries a drafted check-in.

Inputs

Ask the user for these before you start.

  • since: when the last run started, as a time, so only newer tickets are read, e.g. 2026-09-28T09:00:00Z
  • risk_level: the lowest churn-risk level that counts as at risk, e.g. weighing a downgrade or another tool
  • min_confidence: how sure Jev must be before its answer is used without you, e.g. 0.8; a yes-or-no answer counts as yes at or above it and as no at or below 1 minus it
  • risk_tag: the Zendesk tag that marks an at-risk ticket, e.g. churn_risk
  • cs_channel: the Slack channel customer success watches, e.g. #cs-alerts

Set up

Zendesk (tool:zendesk/search, tool:zendesk/update-ticket)

Use the API.

Note: {subdomain} is your Zendesk subdomain, as in acme.zendesk.com. Tokens from OAuth clients created since April 30, 2026 expire after 30 minutes.

Notes:

  • Search tickets, users and organizations: Returns at most 1,000 results per query and 100 per page; for more, use GET /api/v2/search/export.
  • Update a ticket: A comment with public: true is a reply the requester can see; public: false makes it an internal note. This endpoint has its own rate limit and returns 429 when it runs out.

Answer typed questions (TypeSafe AI, tool:typesafe/answer-typed-questions)

Use the API.

Note: Put every question about one record in one request. GET /v1/models lists the models and is the cheapest check of a key; a request over the rate limit gets a 429 with a Retry-After header.

Note: Send state, model (jev-latest) and named questions, each with type, instructions and criteria: a choice maps labels to descriptions, a score lists its levels in order, a noul's is optional. Read a score by its most likely level; send unsure answers to a person.

Search CRM records (HubSpot, tool:hubspot/search-crm-records)

Use the first option your agent supports.

Note: The MCP tool takes up to five groups of six filters and returns up to 200 records per page.

MCP (official, remote)

Add this server to your agent's MCP settings, then sign in when asked.

{ "mcpServers": { "hubspot": { "url": "https://mcp.hubspot.com" } } }

Call the MCP tool search_crm_objects.

API (official)
  • Base URL: https://api.hubapi.com
  • Endpoint: POST /crm/objects/2026-09/{objectType}/search
  • Auth: send the header Authorization: Bearer $HUBSPOT_API_KEY

Note: Use a service key or an app's static access token with the CRM scopes the calls need; paths carry a dated version such as 2026-09.

Slack (tool:slack/find-user-by-email, tool:slack/post-message)

Use the first option your agent supports.

Notes:

  • Find a user by email: Needs the users:read.email scope; a deactivated user returns users_not_found.
  • Post a message: Needs the chat:write scope. Over MCP it posts as the signed-in user; the API and CLI post as the app's bot.
MCP (official, remote)

Add this server to your agent's MCP settings, then sign in when asked.

{ "mcpServers": { "slack": { "url": "https://mcp.slack.com/mcp" } } }
  • Find a user by email: call the MCP tool slack_search_users
  • Post a message: call the MCP tool slack_send_message
CLI (official)

Install the command, then confirm it runs.

curl -fsSL https://downloads.slack-edge.com/slack-cli/install.sh | bash
slack --version
  • Find a user by email: run slack api users.lookupByEmail
  • Post a message: run slack api chat.postMessage

Set $SLACK_BOT_TOKEN in your environment first (get a key: https://api.slack.com/apps).

Before step 1, confirm access to each service with its cheapest read-only call, like a list or a search. Never send or change anything to test access.

Steps

  1. Pull new tickets with Search tickets, users and organizations (Zendesk). Search for tickets (type:ticket) created after since, leaving out those already tagged risk_tag. Keep each ticket's ID, subject, description, priority, tags and requester ID.
  2. Read each ticket with Answer typed questions (TypeSafe AI). Send the subject and description as the state, with a score churn_risk on four levels (no risk; frustrated; weighing a downgrade or another tool; says they will cancel), a choice issue of bug, billing, how_to, missing_feature, performance, access, cancellation and other, a score urgency on three levels (can wait; this week; today), a noul mentions_competitor and a noul asks_for_refund. Keep every answer with its confidence or probability.
  3. Check the unsure ones with the user yourself. Show the user every ticket whose churn_risk confidence is below min_confidence, and keep the level the user picks. Keep the tickets whose most likely churn_risk level is risk_level or higher, and look up each one's requester email, a read-only call.
  4. Find the owner with Search CRM records (HubSpot). Search companies by each at-risk requester's email domain, skipping free email domains. Keep the company's record ID, name and hubspot_owner_id, and look up each owner's name and email, a read-only call. Note the tickets with no match.
  5. Mark the ticket with Update a ticket (Zendesk). After the user approves, add risk_tag alongside each at-risk ticket's existing tags, raise its priority to high, or urgent when its urgency is today, and add an internal note, not a public reply, with the churn-risk level, the issue and the competitor and refund probabilities.
  6. Draft the check-in yourself. Write a short note from each company's owner, by name, that names the problem in the ticket, says what happens next and offers a call, leaving a [fill in] for any fix date or commitment you don't have. Show the drafts to the user.
  7. Find the owners in Slack with Find a user by email (Slack). Look up each owner's email. Keep their Slack user ID.
  8. Alert the owner with Post a message (Slack). Post each at-risk ticket to cs_channel, mentioning its owner, with the company, the churn-risk level, the issue, the competitor and refund probabilities, the ticket ID and the drafted check-in.

Notes

Judge risk by the most likely level, not the expected score. Start with risk_level at weighing a downgrade or another tool, and move it once you have a week of results. Support keeps answering the ticket as usual; the account owner hears about it the same day.

Run it every few hours with since set to the time the previous run started.

Rules

  • Use only the services set up above. The read-only calls they need, like listing ids or polling for results, are fine.
  • Ask the user before anything that sends messages, costs money, or changes data, and say how many records it touches. One approval covers a batch the user has seen.
  • Never print API keys.