Skip to content

HT-6: conversations API v1 spec - #2

Merged
zaridan merged 1 commit into
mainfrom
docs/ht-6-conversation-api-contract
Jul 10, 2026
Merged

HT-6: conversations API v1 spec#2
zaridan merged 1 commit into
mainfrom
docs/ht-6-conversation-api-contract

Conversation

@zaridan

@zaridan zaridan commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

The founding six-operation customer-side contract, derived from what Resonant IQ's production support integration actually consumes (its client code is the de facto contract). Wire shapes compatible with the REST subset it already parses — cutover becomes a base-URL + auth-header swap. Helpthread-native Bearer auth, error envelope, server-enforced validation limits, shared TypeScript shapes.

Six OPEN QUESTIONs flagged for design rather than guessed:

  1. Thread-type semantics (customer/message/note inferred, not observed)
  2. Whether internal notes must be server-filtered from customer-facing reads (real leak risk)
  3. Attachment cap: reject with 400 vs today's silent truncation (found: the cap lives in a slice(0,10), not the validation schema)
  4. Attachment max size / mime allowlist (unspecified anywhere today)
  5. Whether sort/pageSize generalize beyond the single observed combination
  6. Idempotency-key mechanism for create (consumer has no retry protection today)

Proof pass: verified the client's lowercasing and the Conversation.number field against source; fixed create-error semantics (bad mailboxId = 400, not 500); trimmed two defensive asides.

Jira: https://resonantiq.atlassian.net/browse/HT-6

🤖 Generated with Claude Code

https://claude.ai/code/session_01TqG66PPZreBrj17VbAqe3b

Summary by CodeRabbit

  • Documentation
    • Added API v1 documentation for customer conversation workflows.
    • Documented endpoints for listing, viewing, creating, and replying to conversations.
    • Added request and response formats, authentication requirements, error handling, and validation rules.
    • Defined shared schemas for conversations, threads, statuses, and thread types.
    • Clarified supported behavior and current API scope.

Wire-compatible with the REST subset the existing Resonant IQ consumer
speaks (cutover = base URL + auth header), Helpthread-native Bearer
auth, full TypeScript shapes, server-enforced limits, and six flagged
OPEN QUESTIONs (thread-type semantics, internal-note filtering,
attachment reject-vs-truncate, attachment size/mime limits, sort
generalization, create idempotency).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TqG66PPZreBrj17VbAqe3b
@zaridan

zaridan commented Jul 10, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Changes

The pull request adds a Conversations API v1 specification covering six customer-facing operations, shared JSON schemas, authentication and error conventions, validation semantics, authorization expectations, open questions, and explicit non-goals.

Conversations API v1

Layer / File(s) Summary
API conventions and compatibility contract
specs/api/conversations-v1.md
Defines the /api/v1 base path, Bearer authentication, JSON and caching conventions, error responses, pagination behavior, and FreeScout compatibility posture.
Conversation operations and schemas
specs/api/conversations-v1.md
Specifies listing, retrieval, ownership, creation, reply, and customer lookup operations, along with conversation and thread response schemas.
Semantics, validation, and v1 scope
specs/api/conversations-v1.md
Documents email matching, sorting, validation, authorization expectations, open questions, acceptance fixtures, and excluded v1 capabilities.

Estimated code review effort: 2 (Simple) | ~10 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: a conversations API v1 specification document.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch docs/ht-6-conversation-api-contract

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@specs/api/conversations-v1.md`:
- Around line 65-82: Clarify the list-conversations API contract for invalid
pageSize, sortField, sortOrder, and embed query values: specify which values are
accepted and whether invalid inputs return 400 validation_failed, are clamped,
or are ignored. Update the “List conversations by customer email” parameter
notes and pagination/sorting behavior so clients have deterministic validation
and response semantics.
- Around line 211-221: Define customer-facing conversation reads, including GET
/conversations/{id}?embed=threads, as excluding all internal-note and other
agent-only threads; remove the open question and document this as a mandatory
contract invariant. Add an acceptance fixture asserting that note/agent-only
content is absent from the embedded threads response.
- Around line 122-126: Update the v1 attachment contract and its
request-validation rules to define per-file and aggregate decoded-byte limits,
reject malformed base64, and validate MIME types and filenames; document that
any violation returns HTTP 400 with error code validation_failed, covering both
the Attachment interface and the related request fields.
- Around line 193-201: The Thread schema conflates thread kind with author
identity, so agent- and assistant-authored messages cannot be distinguished.
Update the Thread interface to add an explicit actorType field with customer,
agent, and assistant values, while retaining ThreadType for
customer/message/note classification; document the field and ensure the
corresponding schema examples or definitions around the additional referenced
section are updated consistently.
- Around line 241-246: Define the create idempotency contract in the v1
conversation API specification before implementation, including Idempotency-Key
scope, retention period, behavior when the same key is reused with a different
payload, and whether successful or failed responses are replayed. Update the
create endpoint requirements and referenced consumer behavior accordingly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: e8464fb0-a765-41b2-90c3-c3f09714fcfb

📥 Commits

Reviewing files that changed from the base of the PR and between 57a966a and a559e4f.

📒 Files selected for processing (1)
  • specs/api/conversations-v1.md

Comment on lines +65 to +82
- **Pagination:** v1 ships **first-page-only**. `pageSize` is accepted but
capped at 50 (the consumer's only observed value) with no cursor/offset for
a second page — see §5. Sort is newest-first by default and, in v1, the only
supported combination.

## 3. The six operations

### a. List conversations by customer email

`GET /api/v1/conversations?customerEmail={email}&pageSize=50&sortField=createdAt&sortOrder=desc&embed=threads`

| param | type | required | notes |
|---|---|---|---|
| `customerEmail` | string | yes | matched case-insensitively (client always lowercases before sending) |
| `pageSize` | number | no | default 50; v1 hard cap 50 |
| `sortField` | string | no | default `createdAt`; **v1 only supports this value** — see OPEN QUESTION below |
| `sortOrder` | string | no | default `desc`; **v1 only supports this value** |
| `embed` | string | no | `threads` embeds each conversation's threads inline, for list-view previews without an N+1 fetch |

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Define behavior for unsupported query values.

Specify whether invalid pageSize, sortField, sortOrder, and embed values return 400 validation_failed, are clamped, or are ignored. Without this, clients cannot rely on deterministic pagination or sorting behavior.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@specs/api/conversations-v1.md` around lines 65 - 82, Clarify the
list-conversations API contract for invalid pageSize, sortField, sortOrder, and
embed query values: specify which values are accepted and whether invalid inputs
return 400 validation_failed, are clamped, or are ignored. Update the “List
conversations by customer email” parameter notes and pagination/sorting behavior
so clients have deterministic validation and response semantics.

Comment on lines +122 to +126
interface Attachment {
fileName: string;
mimeType: string;
data: string; // base64
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

Define attachment size and content validation before freezing v1.

A limit of ten attachments does not bound the decoded bytes or total request size. Define per-file and aggregate byte limits, reject malformed base64, and specify MIME and filename validation with 400 validation_failed; otherwise this endpoint can be used for oversized payloads and unsafe content.

Also applies to: 230-240

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@specs/api/conversations-v1.md` around lines 122 - 126, Update the v1
attachment contract and its request-validation rules to define per-file and
aggregate decoded-byte limits, reject malformed base64, and validate MIME types
and filenames; document that any violation returns HTTP 400 with error code
validation_failed, covering both the Attachment interface and the related
request fields.

Comment on lines +193 to +201
interface Thread {
id: number;
type: ThreadType;
text: string;
createdAt: string;
createdBy?: { id: number; firstName?: string; lastName?: string };
}

type ThreadType = 'customer' | 'message' | 'note';

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Separate thread kind from actor identity.

The charter requires every thread to record whether it was authored by a customer, agent, or assistant, but this schema only distinguishes customer | message | note. An agent-authored message and an assistant-authored message become indistinguishable. Add an explicit actor field, such as actorType: 'customer' | 'agent' | 'assistant', or revise Thread.type and document the mapping.

Also applies to: 211-217

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@specs/api/conversations-v1.md` around lines 193 - 201, The Thread schema
conflates thread kind with author identity, so agent- and assistant-authored
messages cannot be distinguished. Update the Thread interface to add an explicit
actorType field with customer, agent, and assistant values, while retaining
ThreadType for customer/message/note classification; document the field and
ensure the corresponding schema examples or definitions around the additional
referenced section are updated consistently.

Comment on lines +211 to +221
`type` values on `Thread`: `customer` (customer-authored, the only type the
consumer ever constructs, via create and reply) and `message`/`note` are
included as the actor-facing types implied by the charter's actor vocabulary
(agent-authored reply and internal note, respectively) — **OPEN QUESTION**:
the consumer code read for this spec never parses or renders a thread by
`type`, so the customer/message/note split above is inferred from field
naming and the charter's actor model, not observed. Also **OPEN QUESTION**:
whether `note` threads must ever be filtered out of a customer-facing read
response — an internal note leaking to `GET /conversations/{id}` would be a
real information leak on the agent's behalf, and nothing in the consumer code
proves FreeScout (or should Helpthread) filters this server-side.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Make internal-note filtering a hard contract invariant.

GET /conversations/{id}?embed=threads is customer-facing, yet the schema allows note threads and the spec leaves filtering undecided. Define that internal notes and other agent-only content are excluded from every customer-facing read, then add an acceptance fixture proving the behavior.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@specs/api/conversations-v1.md` around lines 211 - 221, Define customer-facing
conversation reads, including GET /conversations/{id}?embed=threads, as
excluding all internal-note and other agent-only threads; remove the open
question and document this as a mandatory contract invariant. Add an acceptance
fixture asserting that note/agent-only content is absent from the embedded
threads response.

Comment on lines +241 to +246
- **Idempotency for create is unaddressed by the consumer** — it calls create
exactly once per user submit with no client-generated idempotency key or
dedupe logic visible in `actions.ts`. **OPEN QUESTION**: does v1 need an
idempotency-key mechanism (e.g., an `Idempotency-Key` header) to protect
against retry-on-timeout double-creating a conversation? Flagged for design,
not decided here.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Specify create idempotency before implementation.

A request can time out after the conversation is persisted, and a retry can create a duplicate. Define Idempotency-Key semantics, including scope, retention, same-key/different-payload behavior, and replayed responses.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@specs/api/conversations-v1.md` around lines 241 - 246, Define the create
idempotency contract in the v1 conversation API specification before
implementation, including Idempotency-Key scope, retention period, behavior when
the same key is reused with a different payload, and whether successful or
failed responses are replayed. Update the create endpoint requirements and
referenced consumer behavior accordingly.

@zaridan
zaridan merged commit cc957d4 into main Jul 10, 2026
1 check passed
@zaridan
zaridan deleted the docs/ht-6-conversation-api-contract branch August 2, 2026 19:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant