Hub / Design Docs / TSANET-2026-001
TSANET-2026-001 DRAFT

The canonical case model, and how connectors map onto it

Every TSANet connector maps the same canonical collaboration case onto a different platform's data model. This document specifies that canonical model, the places where the write schema and the read schema deliberately diverge, and the mapping decisions each connector has to make. It is for anyone building or reviewing an integration against the Connect API.

Date2026-09-13
Version0.2
AudienceMember integrators
Verified againstConnect API OpenAPI spec

1Background

TSANet Connect exposes one canonical case model. A collaboration between two members is a single case in the platform, and each side sees it through their own connector — as a Salesforce custom object, a Zendesk ticket, a Dataverse row, or an Intercom back-office ticket. The connectors differ in almost everything except this: they all map to and from the same canonical shape.

That makes the canonical model the one contract worth understanding before any platform-specific work. It also makes its sharp edges worth writing down, because every connector has independently had to discover them.

Related Behavioural guidance for working with these endpoints is on Working with the Connect API. Platform-specific mappings are on the individual connector pages. File transfer is specified separately in TSANET-2026-002; every endpoint there is scoped by the token this document introduces.

2Two schemas, one case

The most consequential property of the model is that the shape you write is not the shape you read. Case creation takes a request schema; retrieval returns a status schema; the field names differ between them. This is not a defect, and it is not documented as a mapping anywhere — an integrator meets it when a read-back returns nothing under the names they just sent.

2.1 Field-name divergence

ConceptWrite (create request)Read (case status)
Short problem titleproblemSummarysummary
Full problem textproblemDescriptiondescription
Your own case numberinternalCaseNumbersubmitterCaseNumber or receiverCaseNumber, depending which side you are
Submitter contactsubmitterContactDetails objectflattened onto the case
Counterparty identityimplied by the form targetsubmitCompanyName / receiveCompanyName and their IDs
Test flagtestSubmissiontestCase
Constraint A mapping layer written from the create request alone will fail silently on read-back. Model the two schemas separately and map between them explicitly, rather than assuming one round-trips into the other.

2.2 Fields that only exist on read

The status schema carries lifecycle state the write schema has no concept of: token, status, direction, createdAt and updatedAt, respondBy, and responded. Two of these deserve particular attention.

3Custom fields are data, not schema

Beyond the canonical fields, each partner defines their own intake form. Those fields arrive as a typed template from the form endpoints and are submitted back as a customFields[] array. No connector hardcodes them — the mapping is driven by the template fetched at submission time.

3.1 Form sections

The template groups fields into sections, which is what lets a connector lay the form out sensibly rather than as a flat list:

SectionCarries
PROBLEM_SECTIONThe problem itself — summary, description, severity context
CONTACT_SECTIONWho is asking, and how to reach them
COMMON_CUSTOMER_SECTIONThe shared end customer, where both members serve the same one

That third section is the mechanism for identifying the end customer a collaboration is about. Because it is a partner-defined section rather than a fixed field, a connector that wants to resolve an incoming case to a local account record has to read it as a custom field and map it — there is no canonical endCustomer to bind to.

Constraint Fetch the form template fresh for every submission. Partners change their forms, and the documentId you must submit alongside comes from that same fetch. A cached template means a stale documentId and a rejected case.

3.2 Field types the template can specify

Custom fields are typed — STRING, TEXT, EMAIL, PHONE, INTEGER, URL, SELECT and HIDDEN among them — and a connector is expected to render each appropriately rather than treating everything as free text.

Constraint A SELECT field's options are newline-delimited, not comma-delimited, and the structured selections[] array is frequently empty. Splitting on commas collapses every choice into a single option — a bug that renders perfectly and is wrong. Parse selections[].value first, fall back to splitting on newlines, and only then on commas.

4Where connectors put the data

The canonical model says nothing about storage, and the shipped connectors have made genuinely opposite choices. Both are correct; the difference is worth understanding before designing a new one.

ApproachExampleConsequence
State on the platform's own recordZendesk — custom fields and comments on the ticketFewer objects, native to the agent's view, but collaboration state is entangled with the member's own ticket lifecycle
State in dedicated objectsSalesforce and Dynamics — dedicated case, note and response tables linked to the standard recordThe platform's own record is never modified; collaboration data is separately reportable and separately governed

The second approach has proven easier to reason about at scale, mostly because it keeps a member's existing queues and reporting untouched. The first is lighter to install. Neither is a platform requirement.

Canonical case token is the join key Member A connector own fields, own storage, own note-visibility model Member B connector different platform, same canonical case
Figure 1 — One case, two representations. Neither member sees the other's mapping; the token is what makes them the same case.

5Known mapping gaps

Two mappings are not cleanly expressible today. Both are recorded here so integrators design around them deliberately rather than discovering them mid-build.

5.1 Priority is three levels; most members use four

The canonical model has LOW, MEDIUM and HIGH. Members commonly run a four-level severity scale (S1–S4), so a three-to-four mapping is required in both directions, and it has to stay synchronised across the case lifecycle for both sides' service levels to hold. There is no canonical answer; each connector currently decides its own collapse, which means a case can read as a different severity to each party.

5.2 Note direction is a case property, not a note property

The note object carries no direction field. Notes are written under a synchronisation identity, so author fields are identical regardless of who sent one, and the only available signal is the company name — which is ambiguous when both organisations have similar names. Direction is reliably derivable from the case, not from the note. A connector that labels notes "sent" or "received" should derive that from case direction and its own record of what it posted.

Note A useful convention where both sides agree to it: put a structured event type in the note summary ("status change", "severity change", "new public note") and the human content in description. That gives either side something to build automation on without an API change. It is a convention, not a platform feature.

6Revision history

VersionDateChange
0.22026-09-13Add the testSubmission / testCase row to the divergence table; cross-reference TSANET-2026-002.
0.12026-08-15Initial draft. Field names verified against the OpenAPI specification rather than taken from connector source.