Skip to content
AscendCore
🔌 Integration Guide

Freshservice Integration

Keep Freshservice as your system of record. AscendCore becomes the approval-gated system of action on top: tickets flow in, a human approves in Slack or Teams, the runbook executes, and the decision is written back to the ticket as a private note. No migration.

In one sentence

A Freshservice Workflow Automator rule POSTs new tickets to AscendCore, where the ticket is AI-classified into a runbook, held for explicit human approval, executed against your identity stack, and the outcome lands back on the originating ticket as a private note with an audit-chain reference.

How a ticket flows

  1. Ingest. Your Workflow Automator rule POSTs the ticket number to POST /api/v1/tickets/ingest with a scoped API key. AscendCore then reads the ticket's subject, description, and requester from your Freshservice with the key you connected. One ticket is ingested at most once: retries and rule re-fires return the original run instead of posting a second card.
  2. Classify. AscendCore classifies the ticket text into a runbook intent with a confidence score. Low-confidence or unrecognized tickets are received, audit-logged, and left alone (no_action). Nothing executes on a guess.
  3. Approve. The matching runbook's approval is staged where your organization's approval routing says: a card in your Slack or Teams admin channel, with a threaded note showing the originating ticket number, a link back to it, and the AI's classification and confidence; or, when your organization has no chat channel or chose it, the approval queue in the admin portal, with approvers emailed. A human approves or denies. Every runbook is approval-gated. There is no autonomous path.
  4. Execute. On approval, the runbook runs against your stack (Okta, Entra ID, M365) and the action is recorded on the org's tamper-evident SHA-256 audit chain.
  5. Write back. The decision (approved or denied, by whom, at what time) is appended to the originating ticket as a private note. Your ITSM keeps the complete story.

Step 1: Connect Freshservice

In the admin portal under Integrations, open Freshservice and enter:

Save & verify stores the key in your organization's encrypted vault and reads one ticket to prove the key works. The key is never shown again, and it is used only for your organization. Adding a note is not tested by Verify, because that would change a ticket.

Step 2: Create a scoped AscendCore API key

In the admin portal under API, create a key with the ticket:ingest scope. Least privilege applies: a key with only this scope can submit tickets but cannot execute runbooks directly, read audit rows, or browse the catalog.

You will paste this key into the Automator rule's webhook headers in the next step. It is stored inside the rule, visible only to Freshservice admins who can edit workflows.

Step 3: Add the Workflow Automator rule

In Admin, then Workflow Automator, create an event-based ticket workflow. Drag an Action node after the event and choose Trigger Webhook:

{
  "source": "freshservice",
  "ticket": {
    "ticketId": "{{ticket.id_numeric}}"
  }
}

Only the ticket number is sent. Workflow Automator inserts placeholder values into the body as they are, so a quote or a line break in a subject or description would make the body invalid JSON. AscendCore reads those fields from your Freshservice instead, which also means a request can only refer to a ticket that exists in your account. {{ticket.id_numeric}} is the number the Freshservice API uses; {{ticket.id}} (for example INC-42) is accepted too. Raise a test ticket to confirm a 200 before relying on the rule.

Payload reference

FieldRequiredPurpose
sourceYesMust be "freshservice" for this integration.
ticket.ticketIdYesTicket number (string or number), or the display id such as INC-42. Idempotency key and write-back target.
ticket.subjectOnly without a connectionPrimary classification input. Read from Freshservice when it is connected.
ticket.descriptionNoAppended to the classification input. Read from Freshservice when it is connected.
ticket.urlNoLink back to the ticket, shown to the approver. Built from your connected address when Freshservice is connected.
ticket.requesterEmailNoTarget-user fallback when the ticket text names nobody else. Read from Freshservice (the requester's primary email) when it is connected.

Supported intents in this release

IntentRunbookSystem
MFA resetRB-002Okta
Password resetRB-001Okta
Offboarding (suspend account)RB-011Okta
Account unlockRB-007Microsoft Entra ID
M365 license assignment (a SKU named in the ticket is honored)RB-006M365
Group add / remove (group named in the ticket)RB-013Microsoft Entra ID
New hire provisioning (name and email in the ticket; named groups and license tier honored)RB-003Okta + M365

Tickets that classify to anything else are acknowledged with no_action and audit-logged. Additional intents arrive as additive extensions; your Automator rule does not change.

What the write-back looks like

When the approval reaches a decision (from Slack, Teams, or the dashboard), AscendCore posts a private note on the originating ticket:

[AscendCore] Runbook decision: APPROVED
Runbook: MFA Reset
Target user: Sarah Chen (sarah.chen@acme.com)
Decision by: slack:U0123APPROVER at 2026-06-09T17:42:11.310Z
Completed. The action ran after explicit human approval.
AscendCore run: mfa_1781026931_310000
This decision is recorded on the org's tamper-evident audit chain in AscendCore.

Denied requests get a note too, stating that no changes were made. If the run only partly finished, was stopped by a safety check, or failed, the note says so; it never claims an action that did not run. The note is private (agent-facing, off the requester thread) and is posted with the Freshservice API key your organization connected under Integrations (it needs to add private notes; least privilege applies). The write-back is deliberately non-blocking: if your workspace is unreachable, the approval flow itself is unaffected and the decision remains on the AscendCore audit chain.

Limits and troubleshooting

Security model

Full API reference

The complete request/response contract for POST /api/v1/tickets/ingest (dispositions, error codes, schemas) lives in the OpenAPI reference. Using ServiceNow or Jira instead? See the ServiceNow guide or the Jira guide.