#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.
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:
| Operation | Use it for |
|---|---|
summarise_text | Free-form text (meeting notes, emails, Slack threads). |
summarise_ticket | Structured support tickets (short_description, description, comments, priority…). |
summarise_approval | Pending approvals — what's being decided, deadline, urgency. |
summarise_knowledge_article | Answer 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
| Header | Required | Description |
|---|---|---|
Authorization | Yes | Bearer velgent_live_… — see Authentication. |
Content-Type | Yes | application/json. |
Idempotency-Key | No | Any opaque string ≤ 128 chars. Repeated calls within 24h return the original response. |
#Body
| Field | Type | Required | Description |
|---|---|---|---|
operation | string | Yes | Which prompt to use. See the operations table above or fetch from GET /api/v1/prompts. |
variables | object | Yes¹ | Runtime values for variables the prompt declares. Required ones missing here → 400 with a missing_variables array. Undeclared keys are silently ignored. |
audience | string | No | Hint for who reads the output. Default end_user. Override via variables.audience. |
focus | string | No | Hint for what to emphasise. Default resolution. For summarise_knowledge_article this is the user's question. |
format | string | No | Output style. Free-form — common values: text, summary, bullets, step_by_step, html. Falls back to the prompt's output_format. |
max_tokens | integer | No | Soft cap on summary length. 50–2000. |
include_sentiment | boolean | No | Opt-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_timeline | boolean | No | Opt-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. |
events | array of TicketEvent | No | Structured 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_options | object | No | Per-call timeline knobs (granularity, max_entries, profile). See Timeline options. |
pii_action_override | "REDACT" | "SUPPRESS" | "ALLOW" | null | No | Per-call override of the tenant's PII action policy. |
prompt_template_id | string (UUID) | No | Pin 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
| Field | Type | Description |
|---|---|---|
request_id | string (UUID) | Unique id for this call. Surfaces in your tenant's Activity logs in the admin console. |
summary | string | The summary, in the resolved format. |
intent | object | null | Structured intent — the five built-in fields (see below). Null when model output drifted; logged as schema_drift in your tenant. |
intent_extra | object | null | Custom intent fields declared on the prompt version (see Custom intent fields). Null when none declared, or when the LLM didn't produce them. |
sentiment | object | null | Requester/customer tone. Null unless the request set include_sentiment: true (and the model returned a valid block). See Sentiment. |
timeline | array of TimelineEntry | null | Ordered 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. |
phases | array of PhaseSpan | null | Phase 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. |
format | string | Echo of the resolved format. |
model_used | string | Provider/model that handled this call. Driven by per-tenant model routing. |
redaction_count | integer | Number of PII spans Presidio redacted before the prompt reached the LLM. |
latency_ms | integer | End-to-end latency observed by the engine. |
#intent
The five built-in intent fields — present on every summarise response regardless of operation.
| Field | Type | Description |
|---|---|---|
action_needed | boolean | True if the reader needs to do something. |
action_line | string | null | One-sentence description of the action. |
due_date | string (ISO 8601 date) | null | Deadline mentioned in the source. |
urgency_score | integer (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:
| Type | Example schema | Example 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, notnegative. - 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.
| Field | Type | Description |
|---|---|---|
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. |
score | number (0.0–1.0) | Model confidence in the label. For not_applicable, confidence that no human tone is present. |
rationale | string | null | One-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.
| Field | Type | Required | Description |
|---|---|---|---|
event_id | string | Yes | Stable identifier the timeline cites against. Any opaque string ≤ 128 chars. |
occurred_at | string (ISO 8601 datetime) | Yes | When the event happened. |
actor | string | null | No | Who did it (e.g. alice@acme.com, system). |
actor_role | "requester" | "agent" | "system" | "approver" | null | No | Role of the actor. The first non-system assignment event seeds the triaged phase. |
kind | string | Yes | One of comment, work_note, state_change, field_change, assignment, link, attachment, sla_breach, approval. |
payload | object | No | Native 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.
| Field | Type | Description |
|---|---|---|
event_ids | array of string | Source events this entry rolls up. Always at least one. |
occurred_at | string (ISO 8601 datetime) | When the entry took place (first cited event's time). |
actor | string | null | First cited event's actor. |
actor_role | "requester" | "agent" | "system" | "approver" | null | First cited event's role. |
phase | TimelinePhase | null | Phase this entry belongs to. |
title | string | Short label (1–5 words), e.g. "Diagnosed", "Maintenance applied". |
one_line | string | One sentence describing what happened, grounded in the cited events. |
importance | number (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).
| Field | Type | Description |
|---|---|---|
name | TimelinePhase | Which phase. |
started_at | string (ISO 8601 datetime) | When this span began. |
ended_at | string (ISO 8601 datetime) | null | When the next phase began. Null for the final, open-ended span. |
duration_seconds | integer | null | Length of the span. Null for the final span. |
event_ids | array of string | All cited events inside this span. |
#Phases
V1 ITSM phase taxonomy — 8 phases:
| Phase | Meaning |
|---|---|
reported | Ticket created, no agent action yet. |
triaged | Assigned, priority/category set, but no diagnosis. |
investigated | Agent gathering info — logs, repro, questions. |
diagnosed | Root cause or required action identified. |
remediated | Fix applied (change, restart, config push). |
validated | Requester or test confirmed the fix. |
resolved | Ticket closed with a resolution code. |
reopened | Was 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.
| Field | Type | Default | Description |
|---|---|---|---|
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_grouping | boolean | true | When false, the response's phases array is omitted. |
max_entries | integer | 30 | Cap 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.
| Event | Severity | When |
|---|---|---|
timeline.uncited_entry | warning | Per entry dropped because citations are missing or reference unknown event_ids. |
timeline.truncated | info | Model returned more entries than max_entries; the tail was trimmed. |
timeline.synthesised | info | Free-text fallback — placeholder synth:N event_ids were used because the request omitted events. |
schema_drift (reason: timeline_missing) | warning | include_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:
| Status | Code | When |
|---|---|---|
400 | invalid_request | A required variable is missing. The response body's missing_variables array lists the names. |
400 | invalid_request | operation field absent or empty. |
400 | invalid_request | max_tokens outside 50–2000. |
404 | not_found | The operation key doesn't resolve to a prompt for your tenant. Check GET /api/v1/prompts. |
413 | payload_too_large | Combined 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 →