#Summarise

One endpoint, many prompts. Send content + the operation key naming which prompt to use; get back a summary plus structured intent signals (action needed, due date, urgency, sensitivity) you can route on.

POSThttps://aiengine.velgent.com/api/v1/summarise

For worked requests and example responses across each operation variant, see Examples.

#Operation-as-first-class

Every flavour of summarisation — free-form text, support tickets, approval requests, knowledge-article answers, your tenant's custom prompts — uses the same endpoint. The operation field on the request body selects which prompt template runs.

Platform defaults shipped with every tenant:

OperationUse it for
summarise_textFree-form text (meeting notes, emails, Slack threads).
summarise_ticketStructured support tickets (short_description, description, comments, priority…).
summarise_approvalPending approvals — what's being decided, deadline, urgency.
summarise_knowledge_articleAnswer a user's question against an article. focus is the query.

Operators can author tenant-specific operations in the admin console. Use GET /api/v1/prompts to list everything available to your key.

#Request

HeaderRequiredDescription
AuthorizationYesBearer velgent_live_… — see Authentication.
Content-TypeYesapplication/json.
Idempotency-KeyNoAny opaque string ≤ 128 chars. Repeated calls within 24h return the original response.

#Body

FieldTypeRequiredDescription
operationstringYesWhich prompt to use. See the operations table above or fetch from GET /api/v1/prompts.
variablesobjectYes¹Runtime values for variables the prompt declares. Required ones missing here → 400 with a missing_variables array. Undeclared keys are silently ignored.
audiencestringNoHint for who reads the output. Default end_user. Override via variables.audience.
focusstringNoHint for what to emphasise. Default resolution. For summarise_knowledge_article this is the user's question.
formatstringNoOutput style. Free-form — common values: text, summary, bullets, step_by_step, html. Falls back to the prompt's output_format.
max_tokensintegerNoSoft cap on summary length. 50–2000.
include_sentimentbooleanNoOpt-in. When true, the same call also assesses the tone of the ticket requester/customer and returns it in sentiment. Default false (costs extra output tokens). Works on any operation — see Sentiment.
include_timelinebooleanNoOpt-in. When true, the same call also emits a chronological timeline of significant events on the ticket plus derived phase spans, returned in timeline and phases. Default false (costs extra output tokens). See Timeline.
eventsarray of TicketEventNoStructured ticket events the timeline cites against. Strongly recommended whenever include_timeline is true — every returned entry must reference one or more event_ids from this list. When omitted, the engine falls back to extracting placeholder events from the prose. Max 500 entries per call.
timeline_optionsobjectNoPer-call timeline knobs (granularity, max_entries, profile). See Timeline options.
pii_action_override"REDACT" | "SUPPRESS" | "ALLOW" | nullNoPer-call override of the tenant's PII action policy.
prompt_template_idstring (UUID)NoPin to a specific template id. Mutually exclusive with operation lookup.

¹ Required if the prompt declares any required: true variables.

#Discovering what variables a prompt expects

curl https://aiengine.velgent.com/api/v1/prompts/summarise_ticket/schema \
  -H "Authorization: Bearer $VELGENT_API_KEY"

Returns the declared variables, the auto-injected system_variables, and the version's output_format. Build your request from this.

#Response

FieldTypeDescription
request_idstring (UUID)Unique id for this call. Surfaces in your tenant's Activity logs in the admin console.
summarystringThe summary, in the resolved format.
intentobject | nullStructured intent — the five built-in fields (see below). Null when model output drifted; logged as schema_drift in your tenant.
intent_extraobject | nullCustom intent fields declared on the prompt version (see Custom intent fields). Null when none declared, or when the LLM didn't produce them.
sentimentobject | nullRequester/customer tone. Null unless the request set include_sentiment: true (and the model returned a valid block). See Sentiment.
timelinearray of TimelineEntry | nullOrdered timeline of significant events, each citing the source event_ids it rolls up. Null unless the request set include_timeline: true. Uncited entries are dropped during validation; see Timeline.
phasesarray of PhaseSpan | nullPhase spans derived from the timeline plus deterministic anchors (state transitions, assignment, change-request links). Null when include_timeline is false or no phases could be derived.
formatstringEcho of the resolved format.
model_usedstringProvider/model that handled this call. Driven by per-tenant model routing.
redaction_countintegerNumber of PII spans Presidio redacted before the prompt reached the LLM.
latency_msintegerEnd-to-end latency observed by the engine.

#intent

The five built-in intent fields — present on every summarise response regardless of operation.

FieldTypeDescription
action_neededbooleanTrue if the reader needs to do something.
action_linestring | nullOne-sentence description of the action.
due_datestring (ISO 8601 date) | nullDeadline mentioned in the source.
urgency_scoreinteger (0–10)0 = no urgency, 10 = critical / SLA breach.
sensitivity"low" | "medium" | "high"How sensitive the content is.

#Custom intent fields

Operators can declare additional structured fields on a prompt version in the admin console. Each declared field gets extracted alongside the five built-ins and lands in the response's intent_extra object.

Five field types are supported:

TypeExample schemaExample extracted value
boolean{ "type": "boolean" }true
string{ "type": "string", "nullable": true }"payment-svc" or null
integer{ "type": "integer", "min": 0, "max": 10 }7
enum{ "type": "enum", "values": ["P1","P2","P3","P4"] }"P1"
string_array{ "type": "string_array", "max_items": 5 }["svc-a", "svc-b"]

Each field also carries a description that the LLM sees in the system prompt — write it as you'd explain the field to a new operator.

Use cases:

  • ITSM incident summariser → is_outage_related, affected_service, severity_class
  • Sales-ops summariser → churn_risk_score, competitor_mention, expansion_signal
  • Compliance summariser → regulated_data_present, jurisdiction

The schema is authored on the prompt version in the admin composer (/prompts/[id]/versions/new); the public schema-introspection endpoint GET /api/v1/prompts/{operation}/schema returns the declared schema alongside the existing variables block so callers can discover what custom fields they'll receive.

Cap of 20 custom fields per version. Missing or malformed fields in the LLM response are dropped from intent_extra and logged as schema_drift in your tenant audit log.

#Sentiment

Set include_sentiment: true on the request to have the same LLM call also gauge the emotional tone of the human who raised the ticket — their frustration, anger, or satisfaction — for customer-experience triage. The result lands in the response's sentiment object. It's off by default so calls that don't need it don't pay the extra output tokens, and it works on any operation (the engine injects the sentiment instruction — your prompt template needn't mention it).

Two things it deliberately does not do:

  • It does not infer tone from the technical severity of the incident. A customer calmly reporting a critical outage is neutral, not negative.
  • It does not invent a tone for machine-raised tickets. When the requester is an automated system, monitoring alert, or bot — no human author to read — the label is not_applicable, so an urgent alert isn't misread as an angry customer.
FieldTypeDescription
label"positive" | "neutral" | "negative" | "mixed" | "not_applicable"Requester's emotional tone. mixed when a human's tone swings both ways (grateful for the fix but frustrated it recurred). not_applicable when the ticket was machine-raised.
scorenumber (0.0–1.0)Model confidence in the label. For not_applicable, confidence that no human tone is present.
rationalestring | nullOne-sentence justification, grounded in the content. Null if the model omitted it.
{
  "label":     "negative",
  "score":     0.82,
  "rationale": "Third time the requester has reported this; tone is clearly frustrated."
}

sentiment is null when the flag is off, or when the model's sentiment output drifted from the contract (logged as schema_drift; the summary itself is unaffected).

#Timeline

Set include_timeline: true to have the same call also emit a chronological timeline of significant events on the ticket plus a derived phases list with durations. Useful for handoffs ("what's been tried so far?"), audit replay, and reporting on mean-time-to-each-phase. Off by default so calls that don't need it don't pay the extra output tokens.

The timeline is citation-grounded: every returned entry references one or more event_ids from the request's events array. Uncited or unknown-id entries are dropped during validation and logged in your audit log — the timeline can't fabricate events that didn't exist in the input.

#Two input modes

Structured events[] (recommended). Pass the ticket's activity records — comments, work notes, state changes, assignments, links — and the engine produces citation-grounded entries. This is the path production integrations should use.

Free-text fallback. When events is omitted, the engine synthesises placeholder synth:N event_ids from the prose so citations still resolve. A timeline.synthesised audit event marks the response so operators can distinguish real-event timelines from extracted ones.

#TicketEvent

One entry in the request's events array.

FieldTypeRequiredDescription
event_idstringYesStable identifier the timeline cites against. Any opaque string ≤ 128 chars.
occurred_atstring (ISO 8601 datetime)YesWhen the event happened.
actorstring | nullNoWho did it (e.g. alice@acme.com, system).
actor_role"requester" | "agent" | "system" | "approver" | nullNoRole of the actor. The first non-system assignment event seeds the triaged phase.
kindstringYesOne of comment, work_note, state_change, field_change, assignment, link, attachment, sla_breach, approval.
payloadobjectNoNative fields — e.g. {"body": "..."} for a comment, {"state": {"from": "new", "to": "in_progress"}} for a state change, {"linked": "CHG0099"} for a change-request link.

#TimelineEntry

One entry in the response's timeline array.

FieldTypeDescription
event_idsarray of stringSource events this entry rolls up. Always at least one.
occurred_atstring (ISO 8601 datetime)When the entry took place (first cited event's time).
actorstring | nullFirst cited event's actor.
actor_role"requester" | "agent" | "system" | "approver" | nullFirst cited event's role.
phaseTimelinePhase | nullPhase this entry belongs to.
titlestringShort label (1–5 words), e.g. "Diagnosed", "Maintenance applied".
one_linestringOne sentence describing what happened, grounded in the cited events.
importancenumber (0.0–1.0)Model confidence that this entry advances the story. Filter on this to show only the highlights.

#PhaseSpan

One entry in the response's phases array. Phases form a list, not a strict sequence — a ticket may skip phases (duplicate → resolved) or revisit them (validated → investigated when a fix doesn't hold).

FieldTypeDescription
nameTimelinePhaseWhich phase.
started_atstring (ISO 8601 datetime)When this span began.
ended_atstring (ISO 8601 datetime) | nullWhen the next phase began. Null for the final, open-ended span.
duration_secondsinteger | nullLength of the span. Null for the final span.
event_idsarray of stringAll cited events inside this span.

#Phases

V1 ITSM phase taxonomy — 8 phases:

PhaseMeaning
reportedTicket created, no agent action yet.
triagedAssigned, priority/category set, but no diagnosis.
investigatedAgent gathering info — logs, repro, questions.
diagnosedRoot cause or required action identified.
remediatedFix applied (change, restart, config push).
validatedRequester or test confirmed the fix.
resolvedTicket closed with a resolution code.
reopenedWas resolved, now active again.

Phase boundaries are anchored deterministically by event kind — the LLM doesn't get to invent a "diagnosed" phase that didn't happen. Within each span the LLM picks which event was the narrative moment (e.g. which work note marked the diagnosis).

#Timeline options

Optional timeline_options object on the request.

FieldTypeDefaultDescription
granularity"significant" | "all""significant"significant merges trivial sequences (e.g. three priority bumps in five minutes → one entry). all returns one entry per input event, up to max_entries.
phase_groupingbooleantrueWhen false, the response's phases array is omitted.
max_entriesinteger30Cap on returned entries. 1–200. Excess entries are tail-trimmed; truncation is logged as timeline.truncated.
profile"itsm" | "generic""itsm"Phase taxonomy. generic uses the same 8 phases without the ITSM-specific anchor rules.

#Audit events

Visible in the admin console's Activity logs under your tenant.

EventSeverityWhen
timeline.uncited_entrywarningPer entry dropped because citations are missing or reference unknown event_ids.
timeline.truncatedinfoModel returned more entries than max_entries; the tail was trimmed.
timeline.synthesisedinfoFree-text fallback — placeholder synth:N event_ids were used because the request omitted events.
schema_drift (reason: timeline_missing)warninginclude_timeline was true but the model returned no timeline key.

For a worked request and example response, see Examples → Timeline.

#Errors

Operation-specific errors layered on top of the standard Errors shape:

StatusCodeWhen
400invalid_requestA required variable is missing. The response body's missing_variables array lists the names.
400invalid_requestoperation field absent or empty.
400invalid_requestmax_tokens outside 50–2000.
404not_foundThe operation key doesn't resolve to a prompt for your tenant. Check GET /api/v1/prompts.
413payload_too_largeCombined variable values exceed the engine's input limit.

Missing-variable error body:

{
  "error":             "Required prompt variables not supplied: description",
  "missing_variables": ["description"],
  "operation":         "summarise_ticket",
  "path":              "/api/v1/summarise"
}

Next: Examples →