docs: OpenAPI 3.0 spec (openapi.yaml) for the IIOS API
Machine-readable spec covering all ~44 endpoints across health/dev/interactions/ threads/inbox/support/adapters/routes/ai/calendar with request/response schemas, bearer auth, tenant/consent error codes (400/401/403/404), and reusable enum + DTO components. Validated with @redocly/cli (valid OpenAPI 3.0). Importable into Swagger UI / Postman / Insomnia. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,864 @@
|
||||
openapi: 3.0.3
|
||||
info:
|
||||
title: IIOS — Insignia Interaction OS API
|
||||
version: "0.9.0"
|
||||
description: >
|
||||
REST API for the IIOS service. Everything is an Interaction inside a tenant scope,
|
||||
behind auth/consent/policy gates. Auth is a per-app Bearer JWT (mint dev tokens via
|
||||
POST /v1/dev/token when IIOS_DEV_TOKENS=1). Cross-tenant access returns 403.
|
||||
Companion docs: docs/IIOS_API_AND_SDK_GUIDE.md.
|
||||
servers:
|
||||
- url: http://localhost:3200
|
||||
description: Local dev
|
||||
|
||||
security:
|
||||
- bearerAuth: []
|
||||
|
||||
tags:
|
||||
- name: Health
|
||||
- name: Dev
|
||||
- name: Interactions
|
||||
- name: Threads
|
||||
- name: Inbox
|
||||
- name: Support
|
||||
- name: Adapters
|
||||
- name: Routing
|
||||
- name: AI
|
||||
- name: Calendar
|
||||
|
||||
paths:
|
||||
/health:
|
||||
get:
|
||||
tags: [Health]
|
||||
summary: Liveness + egress provider bindings
|
||||
security: []
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
status: { type: string, example: ok }
|
||||
db: { type: boolean }
|
||||
egressProviders:
|
||||
type: object
|
||||
additionalProperties: { type: string }
|
||||
example: { WEBHOOK: sandbox, EMAIL: http }
|
||||
|
||||
/v1/dev/token:
|
||||
post:
|
||||
tags: [Dev]
|
||||
summary: Mint a dev JWT (requires IIOS_DEV_TOKENS=1)
|
||||
security: []
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required: [appId, userId]
|
||||
properties:
|
||||
appId: { type: string, example: portal-demo }
|
||||
userId: { type: string, example: alice }
|
||||
name: { type: string }
|
||||
orgId: { type: string, description: "Tenant org; default org_<appId>", example: org_A }
|
||||
responses:
|
||||
"201":
|
||||
description: Token
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties: { token: { type: string } }
|
||||
"400": { $ref: "#/components/responses/BadRequest" }
|
||||
|
||||
/v1/dev/webhook/{channelType}:
|
||||
post:
|
||||
tags: [Dev]
|
||||
summary: Inject a server-signed simulated inbound webhook (dev only)
|
||||
security: []
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/channelType"
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
from: { type: string }
|
||||
text: { type: string }
|
||||
responses:
|
||||
"201": { description: Raw inbound event accepted }
|
||||
|
||||
/v1/interactions/ingest:
|
||||
post:
|
||||
tags: [Interactions]
|
||||
summary: Ingest a normalized interaction into the kernel (idempotent by providerEventId)
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: "#/components/schemas/IngestRequest" }
|
||||
responses:
|
||||
"201":
|
||||
description: Created
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties: { interactionId: { type: string } }
|
||||
"400": { $ref: "#/components/responses/BadRequest" }
|
||||
"401": { $ref: "#/components/responses/Unauthorized" }
|
||||
|
||||
/v1/threads/{id}/messages:
|
||||
get:
|
||||
tags: [Threads]
|
||||
summary: List a thread's messages
|
||||
parameters: [{ $ref: "#/components/parameters/idPath" }]
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
threadId: { type: string }
|
||||
messages: { type: array, items: { type: object } }
|
||||
"401": { $ref: "#/components/responses/Unauthorized" }
|
||||
post:
|
||||
tags: [Threads]
|
||||
summary: Send a message (REST fallback for the socket path)
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/idPath"
|
||||
- name: idempotency-key
|
||||
in: header
|
||||
required: false
|
||||
schema: { type: string }
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required: [content]
|
||||
properties:
|
||||
content: { type: string }
|
||||
contentRef: { type: string }
|
||||
responses:
|
||||
"201":
|
||||
description: Message
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: "#/components/schemas/Message" }
|
||||
"400": { $ref: "#/components/responses/BadRequest" }
|
||||
|
||||
/v1/inbox/items:
|
||||
get:
|
||||
tags: [Inbox]
|
||||
summary: List inbox items for the caller
|
||||
parameters:
|
||||
- name: state
|
||||
in: query
|
||||
required: false
|
||||
schema: { $ref: "#/components/schemas/InboxState" }
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema: { type: array, items: { $ref: "#/components/schemas/InboxItem" } }
|
||||
|
||||
/v1/inbox/items/{id}:
|
||||
patch:
|
||||
tags: [Inbox]
|
||||
summary: Transition an inbox item
|
||||
parameters: [{ $ref: "#/components/parameters/idPath" }]
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required: [state]
|
||||
properties:
|
||||
state: { $ref: "#/components/schemas/InboxState" }
|
||||
reason: { type: string }
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: "#/components/schemas/InboxItem" }
|
||||
"404": { $ref: "#/components/responses/NotFound" }
|
||||
|
||||
/v1/support/tickets:
|
||||
post:
|
||||
tags: [Support]
|
||||
summary: Create a ticket
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required: [subject]
|
||||
properties:
|
||||
subject: { type: string }
|
||||
priority: { $ref: "#/components/schemas/TicketPriority" }
|
||||
threadId: { type: string }
|
||||
responses:
|
||||
"201": { description: Ticket, content: { application/json: { schema: { $ref: "#/components/schemas/Ticket" } } } }
|
||||
get:
|
||||
tags: [Support]
|
||||
summary: List tickets
|
||||
parameters:
|
||||
- name: scope
|
||||
in: query
|
||||
required: false
|
||||
schema: { type: string, enum: [mine, assigned], default: mine }
|
||||
responses:
|
||||
"200": { description: OK, content: { application/json: { schema: { type: array, items: { $ref: "#/components/schemas/Ticket" } } } } }
|
||||
|
||||
/v1/support/escalate:
|
||||
post:
|
||||
tags: [Support]
|
||||
summary: Escalate a thread to support (opens a customer↔agent thread)
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required: [threadId]
|
||||
properties:
|
||||
threadId: { type: string }
|
||||
subject: { type: string }
|
||||
responses:
|
||||
"201": { description: Ticket, content: { application/json: { schema: { $ref: "#/components/schemas/Ticket" } } } }
|
||||
|
||||
/v1/support/tickets/{id}:
|
||||
patch:
|
||||
tags: [Support]
|
||||
summary: Transition a ticket
|
||||
parameters: [{ $ref: "#/components/parameters/idPath" }]
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required: [state]
|
||||
properties:
|
||||
state: { $ref: "#/components/schemas/TicketState" }
|
||||
reason: { type: string }
|
||||
responses:
|
||||
"200": { description: Ticket, content: { application/json: { schema: { $ref: "#/components/schemas/Ticket" } } } }
|
||||
"404": { $ref: "#/components/responses/NotFound" }
|
||||
|
||||
/v1/support/callbacks:
|
||||
post:
|
||||
tags: [Support]
|
||||
summary: Request a callback (bridges to a meeting)
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required: [preferChannel]
|
||||
properties:
|
||||
preferChannel: { type: string, example: PHONE }
|
||||
preferredTime: { type: string }
|
||||
notes: { type: string }
|
||||
ticketId: { type: string }
|
||||
responses:
|
||||
"201": { description: CallbackRequest, content: { application/json: { schema: { type: object } } } }
|
||||
|
||||
/v1/support/queues:
|
||||
post:
|
||||
tags: [Support]
|
||||
summary: Create a support queue
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema: { type: object, required: [name], properties: { name: { type: string } } }
|
||||
responses:
|
||||
"201": { description: Queue, content: { application/json: { schema: { type: object, properties: { id: { type: string } } } } } }
|
||||
|
||||
/v1/support/queues/{id}/members:
|
||||
post:
|
||||
tags: [Support]
|
||||
summary: Add the caller to a queue
|
||||
parameters: [{ $ref: "#/components/parameters/idPath" }]
|
||||
responses:
|
||||
"201": { description: Membership }
|
||||
|
||||
/v1/support/agents/me/join:
|
||||
post:
|
||||
tags: [Support]
|
||||
summary: Join the default queue (go online)
|
||||
responses:
|
||||
"201": { description: Membership }
|
||||
|
||||
/v1/support/members/me/availability:
|
||||
patch:
|
||||
tags: [Support]
|
||||
summary: Set the caller's availability
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema: { type: object, required: [state], properties: { state: { type: string, example: AVAILABLE } } }
|
||||
responses:
|
||||
"200": { description: Membership }
|
||||
|
||||
/v1/adapters/{channelType}/webhook:
|
||||
post:
|
||||
tags: [Adapters]
|
||||
summary: Provider inbound webhook (HMAC-signed; async normalize → 202)
|
||||
security: []
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/channelType"
|
||||
- name: x-iios-signature
|
||||
in: header
|
||||
required: true
|
||||
schema: { type: string, example: "sha256=..." }
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema: { type: object, description: raw provider payload }
|
||||
responses:
|
||||
"202": { description: Accepted (normalized asynchronously) }
|
||||
"401": { description: Bad signature }
|
||||
|
||||
/v1/adapters/{channelType}/send:
|
||||
post:
|
||||
tags: [Adapters]
|
||||
summary: Outbound send (through the Capability Broker; sandbox by default)
|
||||
parameters: [{ $ref: "#/components/parameters/channelType" }]
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required: [target]
|
||||
properties:
|
||||
target: { type: string }
|
||||
payload: { type: object }
|
||||
idempotencyKey: { type: string }
|
||||
responses:
|
||||
"201": { description: OutboundCommand, content: { application/json: { schema: { $ref: "#/components/schemas/OutboundCommand" } } } }
|
||||
|
||||
/v1/adapters/inbound:
|
||||
get:
|
||||
tags: [Adapters]
|
||||
summary: List raw inbound events (+ interactionId once normalized)
|
||||
responses:
|
||||
"200": { description: OK, content: { application/json: { schema: { type: array, items: { type: object } } } } }
|
||||
|
||||
/v1/adapters/outbound:
|
||||
get:
|
||||
tags: [Adapters]
|
||||
summary: List outbound commands (+ delivery attempts)
|
||||
responses:
|
||||
"200": { description: OK, content: { application/json: { schema: { type: array, items: { $ref: "#/components/schemas/OutboundCommand" } } } } }
|
||||
|
||||
/v1/routes/bindings:
|
||||
post:
|
||||
tags: [Routing]
|
||||
summary: Create a route binding
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: "#/components/schemas/CreateBinding" }
|
||||
responses:
|
||||
"201": { description: RouteBinding, content: { application/json: { schema: { $ref: "#/components/schemas/RouteBinding" } } } }
|
||||
get:
|
||||
tags: [Routing]
|
||||
summary: List bindings (your scope)
|
||||
responses:
|
||||
"200": { description: OK, content: { application/json: { schema: { type: array, items: { $ref: "#/components/schemas/RouteBinding" } } } } }
|
||||
|
||||
/v1/routes/simulate:
|
||||
post:
|
||||
tags: [Routing]
|
||||
summary: Preview-first simulation (produces decisions, sends nothing)
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required: [interactionId, originChannelType]
|
||||
properties:
|
||||
interactionId: { type: string }
|
||||
originChannelType: { type: string }
|
||||
originRef: { type: string }
|
||||
responses:
|
||||
"201":
|
||||
description: Simulation
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
simulationId: { type: string }
|
||||
decisions: { type: array, items: { $ref: "#/components/schemas/RouteDecision" } }
|
||||
|
||||
/v1/routes/decisions:
|
||||
get:
|
||||
tags: [Routing]
|
||||
summary: List route decisions (your scope)
|
||||
parameters:
|
||||
- name: state
|
||||
in: query
|
||||
required: false
|
||||
schema: { $ref: "#/components/schemas/RouteDecisionState" }
|
||||
responses:
|
||||
"200": { description: OK, content: { application/json: { schema: { type: array, items: { $ref: "#/components/schemas/RouteDecision" } } } } }
|
||||
|
||||
/v1/routes/decisions/{id}/approve:
|
||||
post:
|
||||
tags: [Routing]
|
||||
summary: Approve a REVIEW decision (executes to sandbox)
|
||||
parameters: [{ $ref: "#/components/parameters/idPath" }]
|
||||
responses:
|
||||
"201": { description: RouteDecision, content: { application/json: { schema: { $ref: "#/components/schemas/RouteDecision" } } } }
|
||||
"403": { $ref: "#/components/responses/Forbidden" }
|
||||
"404": { $ref: "#/components/responses/NotFound" }
|
||||
|
||||
/v1/routes/decisions/{id}/deny:
|
||||
post:
|
||||
tags: [Routing]
|
||||
summary: Deny a decision
|
||||
parameters: [{ $ref: "#/components/parameters/idPath" }]
|
||||
responses:
|
||||
"201": { description: RouteDecision, content: { application/json: { schema: { $ref: "#/components/schemas/RouteDecision" } } } }
|
||||
"403": { $ref: "#/components/responses/Forbidden" }
|
||||
|
||||
/v1/routes/bindings/{id}/flush-digest:
|
||||
post:
|
||||
tags: [Routing]
|
||||
summary: Flush a binding's pending DIGEST decisions into one forward
|
||||
parameters: [{ $ref: "#/components/parameters/idPath" }]
|
||||
responses:
|
||||
"201": { description: OK, content: { application/json: { schema: { type: object, properties: { forwarded: { type: integer } } } } } }
|
||||
|
||||
/v1/ai/jobs:
|
||||
post:
|
||||
tags: [AI]
|
||||
summary: Run an AI job (proposes; never decides)
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required: [interactionId, jobType]
|
||||
properties:
|
||||
interactionId: { type: string }
|
||||
jobType: { $ref: "#/components/schemas/AiJobType" }
|
||||
responses:
|
||||
"201":
|
||||
description: Job + proposed artifact
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
job: { type: object }
|
||||
artifact: { $ref: "#/components/schemas/AiArtifact" }
|
||||
|
||||
/v1/ai/artifacts:
|
||||
get:
|
||||
tags: [AI]
|
||||
summary: List AI artifacts (your scope)
|
||||
parameters:
|
||||
- name: interactionId
|
||||
in: query
|
||||
schema: { type: string }
|
||||
- name: status
|
||||
in: query
|
||||
schema: { $ref: "#/components/schemas/AiArtifactStatus" }
|
||||
responses:
|
||||
"200": { description: OK, content: { application/json: { schema: { type: array, items: { $ref: "#/components/schemas/AiArtifact" } } } } }
|
||||
|
||||
/v1/ai/artifacts/{id}:
|
||||
get:
|
||||
tags: [AI]
|
||||
summary: Get an artifact (claims + evidence + modelRun)
|
||||
parameters: [{ $ref: "#/components/parameters/idPath" }]
|
||||
responses:
|
||||
"200": { description: AiArtifact, content: { application/json: { schema: { $ref: "#/components/schemas/AiArtifact" } } } }
|
||||
"403": { $ref: "#/components/responses/Forbidden" }
|
||||
"404": { $ref: "#/components/responses/NotFound" }
|
||||
|
||||
/v1/ai/artifacts/{id}/accept:
|
||||
post:
|
||||
tags: [AI]
|
||||
summary: Accept an artifact (human feedback)
|
||||
parameters: [{ $ref: "#/components/parameters/idPath" }]
|
||||
responses:
|
||||
"201": { description: AiArtifact, content: { application/json: { schema: { $ref: "#/components/schemas/AiArtifact" } } } }
|
||||
"403": { $ref: "#/components/responses/Forbidden" }
|
||||
|
||||
/v1/ai/artifacts/{id}/reject:
|
||||
post:
|
||||
tags: [AI]
|
||||
summary: Reject an artifact
|
||||
parameters: [{ $ref: "#/components/parameters/idPath" }]
|
||||
responses:
|
||||
"201": { description: AiArtifact, content: { application/json: { schema: { $ref: "#/components/schemas/AiArtifact" } } } }
|
||||
"403": { $ref: "#/components/responses/Forbidden" }
|
||||
|
||||
/v1/calendar/meetings:
|
||||
post:
|
||||
tags: [Calendar]
|
||||
summary: Schedule a meeting directly
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: "#/components/schemas/ScheduleMeeting" }
|
||||
responses:
|
||||
"201": { description: Meeting, content: { application/json: { schema: { $ref: "#/components/schemas/Meeting" } } } }
|
||||
get:
|
||||
tags: [Calendar]
|
||||
summary: List meetings (your scope)
|
||||
responses:
|
||||
"200": { description: OK, content: { application/json: { schema: { type: array, items: { $ref: "#/components/schemas/Meeting" } } } } }
|
||||
|
||||
/v1/calendar/requests:
|
||||
post:
|
||||
tags: [Calendar]
|
||||
summary: Create a meeting request (from a callback / AI claim / direct)
|
||||
parameters:
|
||||
- name: fromCallback
|
||||
in: query
|
||||
schema: { type: string }
|
||||
- name: fromClaim
|
||||
in: query
|
||||
schema: { type: string }
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required: [requestedWindow]
|
||||
properties:
|
||||
requestedWindow: { type: object }
|
||||
meetingType: { $ref: "#/components/schemas/MeetingType" }
|
||||
interactionId: { type: string }
|
||||
targetActorId: { type: string }
|
||||
responses:
|
||||
"201": { description: MeetingRequest, content: { application/json: { schema: { type: object } } } }
|
||||
|
||||
/v1/calendar/meetings/{id}:
|
||||
get:
|
||||
tags: [Calendar]
|
||||
summary: Get a meeting (participants, transcripts, summaries, action items)
|
||||
parameters: [{ $ref: "#/components/parameters/idPath" }]
|
||||
responses:
|
||||
"200": { description: Meeting, content: { application/json: { schema: { $ref: "#/components/schemas/Meeting" } } } }
|
||||
"403": { $ref: "#/components/responses/Forbidden" }
|
||||
"404": { $ref: "#/components/responses/NotFound" }
|
||||
|
||||
/v1/calendar/meetings/{id}/consent:
|
||||
post:
|
||||
tags: [Calendar]
|
||||
summary: Set a participant's recording consent
|
||||
parameters: [{ $ref: "#/components/parameters/idPath" }]
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required: [actorRefId, status]
|
||||
properties:
|
||||
actorRefId: { type: string }
|
||||
status: { $ref: "#/components/schemas/ConsentStatus" }
|
||||
responses:
|
||||
"201": { description: Participant }
|
||||
"403": { $ref: "#/components/responses/Forbidden" }
|
||||
|
||||
/v1/calendar/meetings/{id}/transcript:
|
||||
post:
|
||||
tags: [Calendar]
|
||||
summary: Generate a transcript (BLOCKED unless every attendee consented)
|
||||
parameters: [{ $ref: "#/components/parameters/idPath" }]
|
||||
responses:
|
||||
"201":
|
||||
description: Transcript (status READY or BLOCKED)
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
status: { type: string, enum: [READY, BLOCKED, PENDING] }
|
||||
segments: { type: array, items: { type: object } }
|
||||
"403": { $ref: "#/components/responses/Forbidden" }
|
||||
|
||||
/v1/calendar/meetings/{id}/summarize:
|
||||
post:
|
||||
tags: [Calendar]
|
||||
summary: Summarize a READY transcript (AI) + derive action items
|
||||
parameters: [{ $ref: "#/components/parameters/idPath" }]
|
||||
responses:
|
||||
"201": { description: Meeting, content: { application/json: { schema: { $ref: "#/components/schemas/Meeting" } } } }
|
||||
"403": { $ref: "#/components/responses/Forbidden" }
|
||||
|
||||
/v1/calendar/meetings/{id}/action-items:
|
||||
get:
|
||||
tags: [Calendar]
|
||||
summary: List meeting action items
|
||||
parameters: [{ $ref: "#/components/parameters/idPath" }]
|
||||
responses:
|
||||
"200": { description: OK, content: { application/json: { schema: { type: array, items: { type: object } } } } }
|
||||
"403": { $ref: "#/components/responses/Forbidden" }
|
||||
|
||||
/v1/calendar/providers:
|
||||
post:
|
||||
tags: [Calendar]
|
||||
summary: Connect a simulated calendar provider account
|
||||
responses:
|
||||
"201": { description: ProviderAccount, content: { application/json: { schema: { type: object, properties: { id: { type: string } } } } } }
|
||||
|
||||
/v1/calendar/providers/{id}/sync:
|
||||
post:
|
||||
tags: [Calendar]
|
||||
summary: Sync the provider once (deterministic, no network)
|
||||
parameters: [{ $ref: "#/components/parameters/idPath" }]
|
||||
responses:
|
||||
"201": { description: OK, content: { application/json: { schema: { type: object, properties: { pulled: { type: integer }, cursor: { type: string } } } } } }
|
||||
|
||||
components:
|
||||
securitySchemes:
|
||||
bearerAuth:
|
||||
type: http
|
||||
scheme: bearer
|
||||
bearerFormat: JWT
|
||||
|
||||
parameters:
|
||||
idPath:
|
||||
name: id
|
||||
in: path
|
||||
required: true
|
||||
schema: { type: string }
|
||||
channelType:
|
||||
name: channelType
|
||||
in: path
|
||||
required: true
|
||||
schema: { type: string, enum: [WEBHOOK, EMAIL, WHATSAPP, PORTAL] }
|
||||
|
||||
responses:
|
||||
BadRequest:
|
||||
description: Validation error / missing auth / unknown field
|
||||
content: { application/json: { schema: { $ref: "#/components/schemas/Error" } } }
|
||||
Unauthorized:
|
||||
description: Invalid or missing token / bad signature
|
||||
content: { application/json: { schema: { $ref: "#/components/schemas/Error" } } }
|
||||
Forbidden:
|
||||
description: Cross-tenant access — resource not in your scope
|
||||
content: { application/json: { schema: { $ref: "#/components/schemas/Error" } } }
|
||||
NotFound:
|
||||
description: Not found (within your scope)
|
||||
content: { application/json: { schema: { $ref: "#/components/schemas/Error" } } }
|
||||
|
||||
schemas:
|
||||
Error:
|
||||
type: object
|
||||
properties:
|
||||
statusCode: { type: integer }
|
||||
message: { type: string }
|
||||
error: { type: string }
|
||||
|
||||
InboxState: { type: string, enum: [OPEN, SNOOZED, DONE, ARCHIVED, CANCELLED, STALE] }
|
||||
TicketState: { type: string, enum: [NEW, OPEN, PENDING, RESOLVED, CLOSED] }
|
||||
TicketPriority: { type: string, enum: [LOW, NORMAL, HIGH, URGENT] }
|
||||
RouteMode: { type: string, enum: [MANUAL, AUTOMATIC, HYBRID, SIMULATION_ONLY] }
|
||||
OutputFormat: { type: string, enum: [FORWARD, THREADED, DIGEST, SUMMARY, TRANSCRIPT] }
|
||||
RouteDecisionState: { type: string, enum: [ALLOW, DENY, REVIEW, SUPPRESS, SIMULATED] }
|
||||
AiJobType: { type: string, enum: [CLASSIFY, SUMMARIZE, EXTRACT] }
|
||||
AiArtifactStatus: { type: string, enum: [PROPOSED, ACCEPTED, REJECTED, SUPERSEDED] }
|
||||
MeetingType: { type: string, enum: [ZOOM, PHONE, IN_PERSON, CALLBACK, INTERNAL] }
|
||||
ConsentStatus: { type: string, enum: [UNKNOWN, GRANTED, DENIED, REVOKED] }
|
||||
|
||||
IngestRequest:
|
||||
type: object
|
||||
required: [scope, channel, source, parts, occurredAt]
|
||||
properties:
|
||||
scope:
|
||||
type: object
|
||||
required: [orgId, appId]
|
||||
properties:
|
||||
orgId: { type: string }
|
||||
appId: { type: string }
|
||||
buId: { type: string }
|
||||
tenantId: { type: string }
|
||||
workspaceId: { type: string }
|
||||
projectId: { type: string }
|
||||
userScopeId: { type: string }
|
||||
channel:
|
||||
type: object
|
||||
required: [type]
|
||||
properties:
|
||||
type: { type: string }
|
||||
externalChannelId: { type: string }
|
||||
capabilityContract: { type: object }
|
||||
source:
|
||||
type: object
|
||||
required: [handleKind, externalId]
|
||||
properties:
|
||||
handleKind: { type: string }
|
||||
externalId: { type: string }
|
||||
displayName: { type: string }
|
||||
kind: { type: string }
|
||||
thread:
|
||||
type: object
|
||||
properties:
|
||||
externalThreadId: { type: string }
|
||||
subject: { type: string }
|
||||
parts:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
required: [kind]
|
||||
properties:
|
||||
kind: { type: string, example: TEXT }
|
||||
bodyText: { type: string }
|
||||
contentRef: { type: string }
|
||||
mimeType: { type: string }
|
||||
occurredAt: { type: string, format: date-time }
|
||||
providerEventId: { type: string }
|
||||
metadata: { type: object }
|
||||
|
||||
Message:
|
||||
type: object
|
||||
properties:
|
||||
id: { type: string }
|
||||
threadId: { type: string }
|
||||
senderActorId: { type: string }
|
||||
content: { type: string }
|
||||
createdAt: { type: string, format: date-time }
|
||||
|
||||
InboxItem:
|
||||
type: object
|
||||
properties:
|
||||
id: { type: string }
|
||||
ownerActorId: { type: string }
|
||||
kind: { type: string }
|
||||
state: { $ref: "#/components/schemas/InboxState" }
|
||||
title: { type: string }
|
||||
threadId: { type: string }
|
||||
|
||||
Ticket:
|
||||
type: object
|
||||
properties:
|
||||
id: { type: string }
|
||||
subject: { type: string }
|
||||
state: { $ref: "#/components/schemas/TicketState" }
|
||||
priority: { $ref: "#/components/schemas/TicketPriority" }
|
||||
threadId: { type: string }
|
||||
assignedActorId: { type: string }
|
||||
|
||||
OutboundCommand:
|
||||
type: object
|
||||
properties:
|
||||
id: { type: string }
|
||||
channelType: { type: string }
|
||||
target: { type: string }
|
||||
status: { type: string, enum: [PENDING, SENT, FAILED, RATE_LIMITED, BLOCKED] }
|
||||
providerRef: { type: string }
|
||||
consentReceiptRef: { type: string }
|
||||
idempotencyKey: { type: string }
|
||||
|
||||
CreateBinding:
|
||||
type: object
|
||||
required: [originChannelType, destinationChannelType]
|
||||
properties:
|
||||
originChannelType: { type: string }
|
||||
originRef: { type: string }
|
||||
destinationChannelType: { type: string }
|
||||
destinationRef: { type: string }
|
||||
restrictionProfile: { type: string, example: CHILD }
|
||||
mode: { $ref: "#/components/schemas/RouteMode" }
|
||||
outputFormat: { $ref: "#/components/schemas/OutputFormat" }
|
||||
frequency: { type: string }
|
||||
includeAttachments: { type: boolean }
|
||||
requiresReview: { type: boolean }
|
||||
enabled: { type: boolean }
|
||||
|
||||
RouteBinding:
|
||||
allOf:
|
||||
- $ref: "#/components/schemas/CreateBinding"
|
||||
- type: object
|
||||
properties:
|
||||
id: { type: string }
|
||||
|
||||
RouteDecision:
|
||||
type: object
|
||||
properties:
|
||||
id: { type: string }
|
||||
interactionId: { type: string }
|
||||
routeBindingId: { type: string }
|
||||
decisionState: { $ref: "#/components/schemas/RouteDecisionState" }
|
||||
reasonCodes: { type: array, items: { type: string } }
|
||||
previewPayload: { type: object }
|
||||
outputFormat: { $ref: "#/components/schemas/OutputFormat" }
|
||||
executed: { type: boolean }
|
||||
|
||||
AiArtifact:
|
||||
type: object
|
||||
properties:
|
||||
id: { type: string }
|
||||
jobId: { type: string }
|
||||
artifactType: { type: string, enum: [CLASSIFICATION, SUMMARY, TRANSCRIPT, DIGEST, EXTRACTION] }
|
||||
status: { $ref: "#/components/schemas/AiArtifactStatus" }
|
||||
confidence: { type: number, nullable: true }
|
||||
contentRef: { type: object }
|
||||
abstentionReason: { type: string, nullable: true }
|
||||
claims: { type: array, items: { type: object } }
|
||||
evidence: { type: array, items: { type: object } }
|
||||
modelRun: { type: object }
|
||||
|
||||
ScheduleMeeting:
|
||||
type: object
|
||||
required: [meetingType, title, startAt]
|
||||
properties:
|
||||
meetingType: { $ref: "#/components/schemas/MeetingType" }
|
||||
title: { type: string }
|
||||
startAt: { type: string, format: date-time }
|
||||
endAt: { type: string, format: date-time }
|
||||
timezone: { type: string }
|
||||
requestId: { type: string }
|
||||
attendees:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
required: [userId]
|
||||
properties:
|
||||
userId: { type: string }
|
||||
displayName: { type: string }
|
||||
role: { type: string, enum: [REQUIRED, OPTIONAL] }
|
||||
visibility: { type: string, enum: [FULL, LIMITED, NONE] }
|
||||
|
||||
Meeting:
|
||||
type: object
|
||||
properties:
|
||||
id: { type: string }
|
||||
meetingType: { $ref: "#/components/schemas/MeetingType" }
|
||||
status: { type: string, enum: [REQUESTED, SCHEDULED, CONFIRMED, CANCELLED, COMPLETED, NO_SHOW] }
|
||||
title: { type: string }
|
||||
organizerActorId: { type: string }
|
||||
startAt: { type: string, format: date-time, nullable: true }
|
||||
timezone: { type: string }
|
||||
participants: { type: array, items: { type: object } }
|
||||
Reference in New Issue
Block a user