Every processed conversation returns as a vCon conforming to draft-ietf-vcon-vcon-core. The intelligence rides on it as a declared, non-critical extension carried in typed analysis[] objects, each one independently versioned. A system that has never heard of Tresic still parses the conversation and ignores what it does not recognise.
Five things that will otherwise cost you a day. None of them are edge cases; all four of the first are the normal path.
The enriched vCon is an overlay. dialog[] is optional in vcon-core and we do not populate it, so do not write code that assumes a transcript is present. The transcript stays in its authoritative home and is fetched separately by source_call_id, which is preserved verbatim from the input and is your join key back to the source conversation.
Which signals appear in conversation-signals is declared per industry. A signal that is absent from the signals object was never extracted for that industry. That is a different fact from fired: false, which means it was extracted and did not fire. Key on presence before you read the boolean.
Associations to a customer, an employee, a competitor, or a partner are stamped as stable identifiers. Current names and details are resolved at read time through the Customer Data API. This is deliberate: a name change never rewrites a conversation record, and bulk corrections are made by ID.
Reference data is optional per tenant. mapping_status reports mapped, partial, or unmapped, and when an association cannot be resolved the ID is absent rather than guessed. The raw party addresses and source_call_id are always preserved so you can attribute downstream yourself. Aggregate accordingly.
vcon version parameterIt is deprecated in vcon-core and is present only for conformance. Version discovery is per object: read analysis[].type together with its schema tag. Nothing about our release cadence is expressed in that top-level value.
Standard vcon-core members, plus the two fields that make the object joinable and retainable.
| Field | Type | Notes |
|---|---|---|
vcon | string | Core version parameter, deprecated. Always "0.4.0". Never key on it. |
uuid | string | The vCon's own identifier. Stable across re-delivery of the same conversation. |
created_at | RFC 3339 | Always present. |
updated_at | RFC 3339 or null | Null until the object is amended. |
extensions[] | string[] | Lists tresic-enrichment whenever intelligence is attached. |
critical[] | string[] | tresic-enrichment is deliberately not listed, so a consumer that does not understand it may still process the vCon safely. |
parties[] | object[] | Required vcon-core member, always emitted. Per-party role, name, and channel address (tel for voice, SMS and video; mailto for email and chat). This is where raw caller identifiers survive on an unmapped conversation. Join by index to conversation-attribution for resolved IDs. |
source_call_id | string | Preserved verbatim from the input. The join key back to the source conversation and to its transcript. |
pipeline_metadata | object | Provenance only: vertical, the version of the analysis logic for that industry, and data_classification, which drives retention. Deliberately slim. |
analysis[] | object[] | The intelligence, one typed object per output. See below. |
Operational telemetry is not on the wire. Timings, token counts, cost, and processing-strategy internals are ours to run on, not yours to parse.
Each enrichment output is its own vendor-attributed object with its own versioned schema tag. There is no bundle to unpack and no flat mirror of these fields at the top level: read by type.
{
"type": "conversation-signals",
"vendor": "tresic",
"product": "vcon-enrichment",
"schema": "tresic/conversation-signals@1.0",
"encoding": "json",
"body": { /* the type's payload */ }
}
Match on type and vendor: "tresic". A vCon may legitimately carry analysis objects from other vendors alongside ours.
| Type | Schema tag | Always present | What the body carries |
|---|---|---|---|
conversation-classification |
tresic/conversation-classification@1.0 |
Yes | What the conversation is: primary_topic and primary_topic_id with primary_confidence, secondary_topics[], topic_complexity, conversation_type with party counts, disposition, and the physical channel facts (direction, originator, destination). |
conversation-signals |
tresic/conversation-signals@1.0 |
Yes | A normalised risk and opportunity vocabulary. Each signal is an independent {fired, details}, where details is the one-sentence evidence when it fired and null when it did not. Every signal and its definition → |
conversation-resolution |
tresic/conversation-resolution@1.0 |
Yes | resolution is one of resolved, follow_up_required, or no_issue, with resolution_details. Definitions below. |
summary |
standard vcon-core type | Yes | title, plain_text_summary, and action_items[]. Factual recap only: who, why, what, and the outcome. |
sentiment |
standard vcon-core type | Yes | overall_sentiment (positive, neutral, negative) and sentiment_direction (higher, steady, lower), which is the trajectory across the conversation rather than a second reading of it. |
conversation-attribution |
schema not published | Yes | Who the conversation was with, as IDs: customer_id, per-party employee_id, matched competitor_ids and partner_ids, and mapping_status. Carried so you can read it; its schema is tied to our resolver and identifier scheme and is not published. |
conversation-captured-data |
tresic/conversation-captured-data@1.0 |
No | Structured data captured during the conversation, as captures[] of {capture_type, fields}. Emitted only when there was something to capture, so the object's presence is itself the signal that the conversation captured data. Most conversations do not carry it. |
Resolution. resolved means handled to completion on this conversation. follow_up_required means genuinely worked but still pending something - a ticket, a dispatch, a handoff, a callback, an awaited answer. no_issue means there was nothing substantive to resolve. First-contact resolution is therefore resolved / (resolved + follow_up_required), and no_issue is deliberately outside that denominator.
Churn. The churn signal fires on dissatisfaction plus a stated intent to leave. Frustration on its own is a complaint, not churn. This distinction is the field's definition rather than a tuning preference, and a consumer building a retention worklist needs it to read the field correctly.
Emitted by the shipping contract code, values synthesised. One inbound support conversation where two signals fired and the outcome is still open.
{
"vcon": "0.4.0",
"uuid": "36e3298c-7e6f-4045-90bd-b5f693b66c75",
"vcon_id": "36e3298c-7e6f-4045-90bd-b5f693b66c75",
"created_at": "2026-07-24T14:12:07Z",
"updated_at": null,
"extensions": [
"tresic-enrichment"
],
"critical": [],
"parties": [
{
"role": "employee",
"name": "A. Whitfield",
"tel": "204"
},
{
"role": "customer",
"name": "R. Okafor",
"tel": "+15005550142"
}
],
"source_call_id": "8f2c41d0-6a11-4e7b-9c33-2b5e7a441c08",
"pipeline_metadata": {
"vertical": "csps-msps",
"version": "v1.4",
"data_classification": "CLASS_PII"
},
"analysis": [
{
"type": "conversation-classification",
"vendor": "tresic",
"product": "vcon-enrichment",
"schema": "tresic/conversation-classification@1.0",
"encoding": "json",
"body": {
"primary_topic": "Technical Support - Infrastructure & Connectivity",
"primary_topic_id": "T001",
"primary_confidence": 0.93,
"secondary_topics": [
{
"topic": "Account Management & Service Review",
"topic_id": "T005",
"confidence": 0.41
}
],
"topic_complexity": "moderate",
"conversation_type": {
"type": "employee_customer",
"employee_count": 1,
"external_count": 1
},
"direction": "inbound",
"originator": "+15005550142",
"destination": "204",
"disposition": {
"disposition": "standard",
"confidence": 0.98,
"reason": "Substantive two-party business conversation."
}
},
"dialog": null,
"mediatype": null
},
{
"type": "conversation-signals",
"vendor": "tresic",
"product": "vcon-enrichment",
"schema": "tresic/conversation-signals@1.0",
"encoding": "json",
"body": {
"signals": {
"churn": {
"fired": true,
"details": "Customer stated they are being quoted by another provider before renewal."
},
"complaint": {
"fired": true,
"details": "Second fault report in a week; frustration at a repeat visit."
},
"expansion": {
"fired": false,
"details": null
},
"product_request": {
"fired": false,
"details": null
},
"buy_signal": {
"fired": false,
"details": null
}
}
},
"dialog": null,
"mediatype": null
},
{
"type": "conversation-resolution",
"vendor": "tresic",
"product": "vcon-enrichment",
"schema": "tresic/conversation-resolution@1.0",
"encoding": "json",
"body": {
"resolution": "follow_up_required",
"resolution_details": "Field dispatch scheduled; customer awaiting confirmation."
},
"dialog": null,
"mediatype": null
},
{
"type": "summary",
"vendor": "tresic",
"product": "vcon-enrichment",
"schema": "tresic-enrichment/summary@1.0",
"encoding": "json",
"body": {
"title": "Repeat voice quality fault, second report in a week",
"plain_text_summary": "Customer called about dropped calls at their second location, the second report in a week. Engineer confirmed packet loss on the site circuit and raised a field dispatch for 25 July. Customer said they are being quoted by another provider and want the fault resolved before their contract date.",
"action_items": [
{
"action_id": "411a647b-d1b2-43a5-894c-2ccfc5b3a1a2",
"task_type": null,
"description": "Confirm the field dispatch window with the customer",
"owner_role": null,
"owner_name": null,
"priority": "high",
"deadline_suggested": null,
"context": null,
"source_evidence": null,
"crm_action": null,
"follow_up_required": false,
"follow_up_type": null
},
{
"action_id": "5b4b34a1-5b67-48ef-9d86-8f780b638dba",
"task_type": null,
"description": "Review circuit history for the second location before dispatch",
"owner_role": null,
"owner_name": null,
"priority": "medium",
"deadline_suggested": null,
"context": null,
"source_evidence": null,
"crm_action": null,
"follow_up_required": false,
"follow_up_type": null
}
]
},
"dialog": null,
"mediatype": null
},
{
"type": "sentiment",
"vendor": "tresic",
"product": "vcon-enrichment",
"schema": "tresic-enrichment/sentiment@1.0",
"encoding": "json",
"body": {
"overall_sentiment": "negative",
"sentiment_direction": "higher"
},
"dialog": null,
"mediatype": null
},
{
"type": "conversation-attribution",
"vendor": "tresic",
"product": "vcon-enrichment",
"schema": "tresic/conversation-attribution@1.0",
"encoding": "json",
"body": {
"customer_id": {
"external_id": "cus_7Q2M4X",
"identity_provider": null,
"system_of_record": "tresic",
"urn": "tresic:master:cid/cus_7Q2M4X"
},
"customer_match_confidence": "address_name_agree",
"customer_id_alternative": null,
"caller_organization": "Northgate Dental Group",
"competitor_ids": [
{
"external_id": "meridian_voice",
"identity_provider": null,
"system_of_record": "internal",
"urn": "tresic:sor/internal:cid/meridian_voice"
}
],
"partner_ids": [],
"mapping_status": "mapped",
"participants": [
{
"role": "employee",
"employee_id": {
"external_id": "emp_3K9F1B",
"identity_provider": "tresic",
"system_of_record": null,
"urn": "tresic:master:uid/emp_3K9F1B"
},
"employee_match_confidence": "extension_name_agree",
"employee_id_alternative": null
},
{
"role": "customer",
"employee_id": null,
"employee_match_confidence": null,
"employee_id_alternative": null
}
]
},
"dialog": null,
"mediatype": null
}
]
}
Note what this object does not contain: no transcript, no model or processing internals, no resolved customer or employee name, and no signal that this industry does not declare. Those absences are the contract, not gaps in the example.
Each analysis type carries its own semantic version in its schema tag, so types move independently and a change to one never forces a change to your handling of another.
New fields arrive as a minor version bump. Ignore what you do not recognise and something added next quarter cannot break what you shipped this quarter.
A field or enum name is never renamed in place and never repurposed to mean something else. If the meaning changes, the name changes and the version changes with it.
A breaking change is a new major version published as its own schema. The version you integrated against does not shift underneath you.
New signals arrive the same way: as additional entries inside conversation-signals, on the object you already consume. Bringing another industry to production adds classification your existing integration inherits without asking for it.
The vCon container is on the IETF standards track: draft-ietf-vcon-vcon-core defines the JSON format, and our object conforms to it rather than wrapping it.
Because the enrichment is a declared extension on a standard container rather than rows in our database, the conversation and everything derived from it move together, through any tooling that speaks vCon. If you stop working with us, what you hold is still a standard object that still parses.
There is no standard answer yet to "was this resolved" or "what happened that someone should act on." We publish and version those types - classification, signals, resolution, captured data - as the citable contract, and every conversation we process is a reference implementation of them. Tresic contributes to the vCon work at the IETF and to the CPaaS Acceleration Alliance AI and Data working group.
API access comes with credentials against a sandbox tenant and a corpus to build against, so you can read real objects rather than reason about a specification.