GraphQL Schema
ThinkWork exposes a GraphQL API with two endpoints:
- API Gateway — Queries and mutations. HTTP POST. Protected by Cognito JWT.
- AppSync — Real-time subscriptions. WebSocket. Protected by Cognito JWT.
Both endpoints share the same schema. Use API Gateway for most operations, and connect to AppSync when you need live updates (streaming agent responses, thread status changes).
Endpoints
Section titled “Endpoints”# From CLI outputs:thinkwork outputs -s dev
# API Gateway (queries + mutations)POST https://<id>.execute-api.<region>.amazonaws.com/graphql
# AppSync (subscriptions)wss://<id>.appsync-realtime-api.<region>.amazonaws.com/graphql# HTTP (for queries/mutations via AppSync if preferred)https://<id>.appsync-api.<region>.amazonaws.com/graphqlAuthentication
Section titled “Authentication”All API calls require a Cognito JWT in the Authorization header:
curl -X POST https://<api-gw-url>/graphql \ -H "Authorization: Bearer <cognito-id-token>" \ -H "Content-Type: application/json" \ -d '{"query": "{ listAgents { items { id name } } }"}'Obtain a token by signing in to Cognito:
aws cognito-idp initiate-auth \ --auth-flow USER_PASSWORD_AUTH \ --client-id <cognito-client-id> \ --auth-parameters USERNAME=user@example.com,PASSWORD=password \ --query 'AuthenticationResult.IdToken' \ --output textCore types
Section titled “Core types”type Agent { id: ID! name: String! description: String status: AgentStatus! # created | active | suspended | archived systemPrompt: String templateId: ID template: AgentTemplate skillPackIds: [ID!] knowledgeBaseId: ID rateLimits: RateLimits createdAt: AWSDateTime! updatedAt: AWSDateTime!}Thread
Section titled “Thread”type Thread { id: ID! # e.g. "CHAT-0042" threadUUID: ID! # Internal UUID prefix: String! # e.g. "CHAT" channel: ThreadChannel! # CHAT | AUTO | EMAIL | SLACK | GITHUB | TASK | EVAL status: ThreadStatus! # open | closed | failed | waiting title: String agentId: ID! agent: Agent messages(limit: Int, nextToken: String): MessageConnection! metadata: AWSJSON tokenCount: Int # Approximate total tokens in thread createdAt: AWSDateTime! updatedAt: AWSDateTime!}Message
Section titled “Message”type Message { id: ID! threadId: ID! role: MessageRole! # user | assistant | system | tool body: String! # Markdown text toolCalls: [ToolCall!] toolResults: [ToolResult!] tokenCount: Int model: String # Bedrock model ID (assistant messages only) createdAt: AWSDateTime!}Key queries
Section titled “Key queries”Agents
Section titled “Agents”# List all active agentsquery ListAgents { listAgents(filter: { status: active }, limit: 20) { items { id name status template { modelId } } nextToken }}
# Get a single agentquery GetAgent { getAgent(id: "agent-abc123") { id name systemPrompt skillPackIds knowledgeBaseId rateLimits { turnsPerMinute turnsPerHour turnsPerDay } }}Threads
Section titled “Threads”# List threadsquery ListThreads { listThreads(filter: { channel: CHAT status: open agentId: "agent-abc123" }, limit: 20) { items { id title status updatedAt } nextToken }}
# Get thread with messagesquery GetThread { getThread(id: "CHAT-0042") { id title status channel metadata messages(limit: 50) { items { id role body createdAt tokenCount } } }}Key mutations
Section titled “Key mutations”Threads and messages
Section titled “Threads and messages”# Create a threadmutation CreateThread { createThread(input: { channel: CHAT title: "Support request" agentId: "agent-support" metadata: "{\"source\": \"web\"}" }) { id prefix status }}
# Send a message (triggers agent invoke)mutation SendMessage { sendMessage(input: { threadId: "CHAT-0042" body: "How do I reset my password?" }) { id role body createdAt }}
# Close a threadmutation CloseThread { updateThread(id: "CHAT-0042", input: { status: closed }) { id status updatedAt }}Agents
Section titled “Agents”mutation CreateAgent { createAgent(input: { name: "Support Bot" systemPrompt: "You are a helpful support agent." templateId: "tpl-claude-sonnet" skillPackIds: ["sp-jira", "sp-confluence"] knowledgeBaseId: "kb-support" }) { id status }}
mutation UpdateAgent { updateAgent(id: "agent-abc123", input: { systemPrompt: "Updated system prompt." skillPackIds: ["sp-jira"] }) { id updatedAt }}Subscriptions
Section titled “Subscriptions”Connect to AppSync WebSocket to receive real-time events. All subscriptions require Cognito JWT authentication via the header connection parameter.
Subscribe to a thread
Section titled “Subscribe to a thread”subscription OnThreadEvent { onThreadEvent(threadId: "CHAT-0042") { ... on NewMessageEvent { message { id role body createdAt } } ... on AgentStatusEvent { agentId status # thinking | calling_tool | streaming | idle activity # Human-readable activity description } ... on ThreadUpdateEvent { thread { id status updatedAt } } ... on StreamChunkEvent { messageId chunk # Partial text chunk (for streaming responses) done # True when streaming is complete } }}Subscribe to agent activity
Section titled “Subscribe to agent activity”subscription OnAgentActivity { onAgentActivity(agentId: "agent-support") { threadId status activity timestamp }}Subscription event types
Section titled “Subscription event types”| Event | Payload | When emitted |
|---|---|---|
NewMessageEvent | Full message object | When a message is added to the thread (user or agent) |
AgentStatusEvent | agentId, status, activity | When agent state changes (thinking, tool call, done) |
ThreadUpdateEvent | Thread object | When thread status, title, or metadata changes |
StreamChunkEvent | messageId, chunk, done | As the agent streams each text chunk |
AgentStatus values
Section titled “AgentStatus values”| Status | Meaning |
|---|---|
idle | Agent is not processing |
thinking | Agent is waiting for Bedrock response |
calling_tool | Agent is executing a tool call |
streaming | Agent is streaming the final response |
error | Agent encountered an error |
Pagination
Section titled “Pagination”List queries return a Connection type with items and nextToken:
type ThreadConnection { items: [Thread!]! nextToken: String # Pass to next request to get the next page}Pass nextToken to paginate:
query ListThreadsPage2 { listThreads(limit: 20, nextToken: "eyJpZCI6Ikc...") { items { id title } nextToken # null when no more pages }}Error handling
Section titled “Error handling”GraphQL errors follow the standard format:
{ "errors": [ { "message": "Thread CHAT-9999 not found", "errorType": "NotFound", "locations": [{ "line": 2, "column": 3 }], "path": ["getThread"] } ]}Common error types:
| errorType | HTTP status | Meaning |
|---|---|---|
Unauthorized | 401 | Missing or invalid JWT |
Forbidden | 403 | JWT valid but insufficient permissions |
NotFound | 404 | Resource doesn’t exist |
ValidationError | 400 | Input validation failed |
RateLimitExceeded | 429 | Agent rate limit hit |
BudgetExceeded | 429 | Agent budget exceeded |
InternalError | 500 | Unexpected server error |