Melso Docs

Messages and interactions

Verified request, response and authorization contracts.

Use /input to request execution. /messages posts discussion without scheduling a Run. On task.needs_input, fetch the interaction identified by the event and answer as its recipient. Answering or declining can enqueue a continuation Run; use the Task ID to track it.

A completed Run’s reply is the newest assistant message whose run_id is that Run’s ID. Melso stores it with secret-looking values redacted. A reply that arrives double-escaped, with no real line break inside it but \n or \r escape sequences in its place, is decoded (\n, \r, \t and \\); leading and trailing line breaks do not count. Any single-line reply that contains \n or \r is decoded the same way, including a path such as C:\new\folder. Other replies keep their backslashes, so code and paths in a multi-line answer stay intact. The Run’s result.output keeps the raw harness text, so read the reply from the messages. kind: "no_response" marks a Run that finished without text or attachments, and a message with failure_reason reports a Run that stopped.

Examples use the environment variables from Overview. UUID placeholders must be replaced with your own IDs.

POST /api/tasks/{id}/input

Auth: Workspace member with access to this resource.

Request: content:string required (not blank, no NUL characters), attachment_ids?:UUID[], client_request_id?:UUID, fresh_session?:boolean, max_attempts?:1. Task path must be a UUID. The JSON body is limited to 1 MiB, and unknown fields are rejected.

Response: TaskInputResponse.

Status: 201, also for a replay; 400 blank or invalid content, an unknown field or a field of the wrong type, max_attempts other than 1, or a client_request_id that is not a UUID; 413 body over 1 MiB; 409 cancelled Task, missing execution settings, or a client_request_id already used with a different payload ("code":"client_request_conflict"). Authentication and resource-access errors follow Overview.

fresh_session and max_attempts configure the Run this input creates. With fresh_session: true the Run starts a new harness session instead of resuming the Task's previous one; it still receives the Task's recent messages. Omitted or false, the Run resumes unless the sender, harness or execution settings changed. max_attempts is execution.max_attempts of POST /api/tasks for this Run: 1 gives it a single attempt, with no automatic retry and no Cloud lifetime rollover; omitted or null keeps the default of two attempts. Both hold when the Run waits in the queue behind other work, and for its retries: a retry of a fresh_session Run continues the session that Run started, or starts fresh again when it started none.

Send a fresh UUID as client_request_id on every send and reuse it when you retry after a network error, timeout or 5xx. A retry with the same content, attachment_ids (compared as a set), fresh_session and max_attempts sends nothing again; an omitted option equals its default (false, null). It returns 201 with the original message_id, run_id, queued, attachment_ids and created_at, even after the Task completed, was cancelled or lost its execution target. Identical requests sent concurrently create one message and one Run. The ID is scoped to the Task and to the caller that sent it: another member, workspace API key or Run using the same ID sends its own input, and your access to the Task is checked again before a retry is answered. A send that failed committed nothing, so retrying it with the same ID sends it.

curl -sS -X POST "$MELSO_URL/api/tasks/$ID/input" \
  -H "Authorization: Bearer $MELSO_TOKEN" -H "X-Workspace-ID: $WORKSPACE_ID" \
  -H "Content-Type: application/json" \
  -d '{"content":"Include operating costs.","client_request_id":"8b2f6c1e-4a7d-4f5e-9c3b-1d2e3f4a5b6c"}'

A workflow step that starts without the previous step's session and is never retried automatically:

curl -sS -X POST "$MELSO_URL/api/tasks/$ID/input" \
  -H "Authorization: Bearer $MELSO_TOKEN" -H "X-Workspace-ID: $WORKSPACE_ID" \
  -H "Content-Type: application/json" \
  -d '{"content":"Publish the approved draft.","fresh_session":true,"max_attempts":1,"client_request_id":"3c9e1f4a-7b2d-4e8f-a1c6-5d0b9e2f7a41"}'

GET /api/tasks/{id}/messages

Auth: Workspace member with access to this resource.

Request: Path: Task ID. No pagination.

Response: TaskMessageResponse array holding the oldest 2000 messages, oldest first. A longer conversation’s newest messages are missing here; read them from the page route below.

Status: 200. Authentication and resource-access errors follow Overview.

curl -sS -X GET "$MELSO_URL/api/tasks/$ID/messages" \
  -H "Authorization: Bearer $MELSO_TOKEN" -H "X-Workspace-ID: $WORKSPACE_ID"

GET /api/tasks/{id}/messages/page

Auth: Workspace member with access to this resource.

Request: Path: Task UUID. Query: limit?:integer, before_created_at?:RFC3339Nano, before_id?:UUID (cursor pair).

Response: TaskMessagesPageResponse; default limit 50, valid range 1–100, chronological order within each page. The first page, without a cursor, holds the newest messages. For older ones, pass next_cursor.created_at and next_cursor.id as before_created_at and before_id while has_more is true. Queued follow-ups that are not yet next in line are omitted.

Status: 200; 400 invalid limit or cursor. Authentication and resource-access errors follow Overview.

curl -sS -X GET "$MELSO_URL/api/tasks/$ID/messages/page" \
  -H "Authorization: Bearer $MELSO_TOKEN" -H "X-Workspace-ID: $WORKSPACE_ID"

POST /api/tasks/{id}/messages

Auth: Workspace member with access to this resource.

Request: content:string, attachment_ids?:UUID[].

Response: TaskMessageResponse. A member’s message reopens a completed Task but never starts a Run.

Status: 201; 400 empty content/invalid attachments; 409 cancelled Task. Authentication and resource-access errors follow Overview.

curl -sS -X POST "$MELSO_URL/api/tasks/$ID/messages" \
  -H "Authorization: Bearer $MELSO_TOKEN" -H "X-Workspace-ID: $WORKSPACE_ID" \
  -H "Content-Type: application/json" -d '{"content":"For reference: the budget is approved."}'

PUT /api/task-messages/{messageId}

Auth: Workspace member with access to this resource.

Request: content:string, optional attachment_ids:UUID[]; the author or a workspace owner/admin.

Response: TaskMessageResponse.

Status: 200; 400 invalid content; 403 neither author nor admin. Authentication and resource-access errors follow Overview.

curl -sS -X PUT "$MELSO_URL/api/task-messages/$MESSAGE_ID" \
  -H "Authorization: Bearer $MELSO_TOKEN" -H "X-Workspace-ID: $WORKSPACE_ID" \
  -H "Content-Type: application/json" -d '{"content":"Updated note."}'

DELETE /api/task-messages/{messageId}

Auth: Workspace member with access to this resource.

Request: Path: message UUID; the author or a workspace owner/admin.

Response: Empty.

Status: 204; 403 neither author nor admin; 409 message already used for execution. Authentication and resource-access errors follow Overview.

curl -sS -X DELETE "$MELSO_URL/api/task-messages/$MESSAGE_ID" \
  -H "Authorization: Bearer $MELSO_TOKEN" -H "X-Workspace-ID: $WORKSPACE_ID"

GET /api/tasks/{id}/interactions

Auth: Workspace member with access to this resource.

Request: Path: Task ID.

Response: InteractionRequestResponse array.

Status: 200. Authentication and resource-access errors follow Overview.

curl -sS -X GET "$MELSO_URL/api/tasks/$ID/interactions" \
  -H "Authorization: Bearer $MELSO_TOKEN" -H "X-Workspace-ID: $WORKSPACE_ID"

POST /api/tasks/{id}/interactions

Auth: Workspace member with access to this resource.

Request: kind:"clarification"|"approval", title?:string, message:string, payload:object, recipient_user_id?:UUID, parent_message_id?:UUID, expires_at?:RFC3339.

Response: InteractionRequestResponse.

Status: 201 created; 200 existing request; 400 invalid payload; 403 invalid source Run. Authentication and resource-access errors follow Overview.

curl -sS -X POST "$MELSO_URL/api/tasks/$ID/interactions" \
  -H "Authorization: Bearer $MELSO_TOKEN" -H "X-Workspace-ID: $WORKSPACE_ID" \
  -H "Content-Type: application/json" -d '{"kind":"approval","title":"Publish","message":"Publish the draft?","payload":{"version":1}}'

GET /api/tasks/{id}/interactions/{interactionId}

Auth: Workspace member with access to this resource.

Request: Path: interaction UUID (and Task ID for the scoped route).

Response: InteractionRequestResponse.

Status: 200. Authentication and resource-access errors follow Overview.

curl -sS -X GET "$MELSO_URL/api/tasks/$ID/interactions/$INTERACTION_ID" \
  -H "Authorization: Bearer $MELSO_TOKEN" -H "X-Workspace-ID: $WORKSPACE_ID"

POST /api/tasks/{id}/interactions/{interactionId}/respond

Auth: Respond/decline: the authenticated recipient, or a current workspace owner or admin. The responder is recorded and supplies authority for any continuation Run. Cancel: authorized member, or the original active source Run.

Request: response:object for respond; optional audit_text:string. Approval response uses decision:"approve_once"|"deny"|"decline"; clarification uses answers:object keyed by question IDs.

Response: InteractionRequestResponse.

Status: 200; 400 invalid answers; 403 actor/recipient mismatch; 409 already resolved or continuation conflict. Authentication and resource-access errors follow Overview.

curl -sS -X POST "$MELSO_URL/api/tasks/$ID/interactions/$INTERACTION_ID/respond" \
  -H "Authorization: Bearer $MELSO_TOKEN" -H "X-Workspace-ID: $WORKSPACE_ID" \
  -H "Content-Type: application/json" -d '{"response":{"decision":"approve_once"}}'

POST /api/tasks/{id}/interactions/{interactionId}/decline

Auth: Respond/decline: the authenticated recipient, or a current workspace owner or admin. The responder is recorded and supplies authority for any continuation Run. Cancel: authorized member, or the original active source Run.

Request: response:object for respond; optional audit_text:string. Approval response uses decision:"approve_once"|"deny"|"decline"; clarification uses answers:object keyed by question IDs.

Response: InteractionRequestResponse.

Status: 200; 400 invalid answers; 403 actor/recipient mismatch; 409 already resolved or continuation conflict. Authentication and resource-access errors follow Overview.

curl -sS -X POST "$MELSO_URL/api/tasks/$ID/interactions/$INTERACTION_ID/decline" \
  -H "Authorization: Bearer $MELSO_TOKEN" -H "X-Workspace-ID: $WORKSPACE_ID" \
  -H "Content-Type: application/json" -d '{"audit_text":"No longer needed."}'

POST /api/tasks/{id}/interactions/{interactionId}/cancel

Auth: Respond/decline: the authenticated recipient, or a current workspace owner or admin. The responder is recorded and supplies authority for any continuation Run. Cancel: authorized member, or the original active source Run.

Request: response:object for respond; optional audit_text:string. Approval response uses decision:"approve_once"|"deny"|"decline"; clarification uses answers:object keyed by question IDs.

Response: InteractionRequestResponse.

Status: 200; 400 invalid answers; 403 actor/recipient mismatch; 409 already resolved or continuation conflict. Authentication and resource-access errors follow Overview.

curl -sS -X POST "$MELSO_URL/api/tasks/$ID/interactions/$INTERACTION_ID/cancel" \
  -H "Authorization: Bearer $MELSO_TOKEN" -H "X-Workspace-ID: $WORKSPACE_ID" \
  -H "Content-Type: application/json" -d '{"audit_text":"No longer needed."}'

GET /api/interactions/{interactionId}

Auth: Workspace member with access to this resource.

Request: Path: interaction UUID (and Task ID for the scoped route).

Response: InteractionRequestResponse.

Status: 200. Authentication and resource-access errors follow Overview.

curl -sS -X GET "$MELSO_URL/api/interactions/$INTERACTION_ID" \
  -H "Authorization: Bearer $MELSO_TOKEN" -H "X-Workspace-ID: $WORKSPACE_ID"

POST /api/interactions/{interactionId}/respond

Auth: Respond/decline: the authenticated recipient, or a current workspace owner or admin. The responder is recorded and supplies authority for any continuation Run. Cancel: authorized member, or the original active source Run.

Request: response:object for respond; optional audit_text:string. Approval response uses decision:"approve_once"|"deny"|"decline"; clarification uses answers:object keyed by question IDs.

Response: InteractionRequestResponse.

Status: 200; 400 invalid answers; 403 actor/recipient mismatch; 409 already resolved or continuation conflict. Authentication and resource-access errors follow Overview.

curl -sS -X POST "$MELSO_URL/api/interactions/$INTERACTION_ID/respond" \
  -H "Authorization: Bearer $MELSO_TOKEN" -H "X-Workspace-ID: $WORKSPACE_ID" \
  -H "Content-Type: application/json" -d '{"response":{"decision":"approve_once"}}'

POST /api/interactions/{interactionId}/decline

Auth: Respond/decline: the authenticated recipient, or a current workspace owner or admin. The responder is recorded and supplies authority for any continuation Run. Cancel: authorized member, or the original active source Run.

Request: response:object for respond; optional audit_text:string. Approval response uses decision:"approve_once"|"deny"|"decline"; clarification uses answers:object keyed by question IDs.

Response: InteractionRequestResponse.

Status: 200; 400 invalid answers; 403 actor/recipient mismatch; 409 already resolved or continuation conflict. Authentication and resource-access errors follow Overview.

curl -sS -X POST "$MELSO_URL/api/interactions/$INTERACTION_ID/decline" \
  -H "Authorization: Bearer $MELSO_TOKEN" -H "X-Workspace-ID: $WORKSPACE_ID" \
  -H "Content-Type: application/json" -d '{"audit_text":"No longer needed."}'

POST /api/interactions/{interactionId}/cancel

Auth: Respond/decline: the authenticated recipient, or a current workspace owner or admin. The responder is recorded and supplies authority for any continuation Run. Cancel: authorized member, or the original active source Run.

Request: response:object for respond; optional audit_text:string. Approval response uses decision:"approve_once"|"deny"|"decline"; clarification uses answers:object keyed by question IDs.

Response: InteractionRequestResponse.

Status: 200; 400 invalid answers; 403 actor/recipient mismatch; 409 already resolved or continuation conflict. Authentication and resource-access errors follow Overview.

curl -sS -X POST "$MELSO_URL/api/interactions/$INTERACTION_ID/cancel" \
  -H "Authorization: Bearer $MELSO_TOKEN" -H "X-Workspace-ID: $WORKSPACE_ID" \
  -H "Content-Type: application/json" -d '{"audit_text":"No longer needed."}'

TaskMessageResponse

Source: server/internal/handler/task_message.go (TaskMessageResponse). Referenced nested objects retain their handler-defined fields; clients should tolerate additional fields.

FieldJSON type
idstring
task_idstring
author_typestring
author_idstring
contentstring
rolestring
kindstring
run_idstring or null (may be omitted)
failure_reasonstring or null (may be omitted)
elapsed_msinteger or null (may be omitted)
created_atstring
updated_atstring
reactionsReactionResponse[]
attachmentsAttachmentResponse[]
finalboolean or null (may be omitted)

InteractionRequestResponse

Source: server/internal/handler/interaction_request.go (InteractionRequestResponse). Referenced nested objects retain their handler-defined fields; clients should tolerate additional fields.

FieldJSON type
idstring
workspace_idstring
task_idstring
source_run_idstring or null
parent_message_idstring or null
recipient_user_idstring
kindstring
statusstring
titlestring or null
messagestring
payloadJSON
responseJSON
audit_textstring or null
response_actor_typestring or null
response_actor_idstring or null
expires_atstring or null
resolved_atstring or null
created_atstring
updated_atstring

TaskInputResponse

Source: server/internal/handler/task_input.go (TaskInputResponse). Referenced nested objects retain their handler-defined fields; clients should tolerate additional fields.

FieldJSON type
message_idstring
run_idstring
queuedboolean
attachment_idsstring[] or null: the attachments bound to the message; null when the request named none
created_atstring

TaskMessagesPageResponse

Source: server/internal/handler/task_input.go (TaskMessagesPageResponse). Referenced nested objects retain their handler-defined fields; clients should tolerate additional fields.

FieldJSON type
messagesTaskMessageResponse[]
limitinteger
has_moreboolean
next_cursorTaskMessagesCursorResponse or null (may be omitted)

TaskMessagesCursorResponse

Source: server/internal/handler/task_input.go (TaskMessagesCursorResponse). Referenced nested objects retain their handler-defined fields; clients should tolerate additional fields.

FieldJSON type
created_atstring
idstring

GET /api/tasks/{id}/timeline

Auth: Workspace member with access to this resource.

Request: No pagination. Legacy limit, before, after, around queries are rejected.

Response: TimelineEntry array in ascending time order; comments and activities capped separately at 2000 each. X-Timeline-Truncated reports truncation.

Status: 200; 400 pagination unsupported. Authentication and resource-access errors follow Overview.

curl -sS -X GET "$MELSO_URL/api/tasks/$ID/timeline" \
  -H "Authorization: Bearer $MELSO_TOKEN" -H "X-Workspace-ID: $WORKSPACE_ID"

TimelineEntry

Source: server/internal/handler/activity.go (TimelineEntry). Referenced nested objects retain their handler-defined fields; clients should tolerate additional fields.

FieldJSON type
typestring
idstring
actor_typestring
actor_idstring
created_atstring
actionstring or null (may be omitted)
detailsJSON (may be omitted)
contentstring or null (may be omitted)
parent_idstring or null (may be omitted)
updated_atstring or null (may be omitted)
comment_typestring or null (may be omitted)
reactionsReactionResponse[] (may be omitted)
attachmentsAttachmentResponse[] (may be omitted)
resolved_atstring or null (may be omitted)
resolved_by_typestring or null (may be omitted)
resolved_by_idstring or null (may be omitted)
run_idstring or null (may be omitted)

Clarification payloads

payload.questions contains 1–20 objects with unique id:string, label:string, type:string, optional required:boolean, and options:[{value:string,label:string}] for selection types. Supported types are text, textarea, date, boolean, number, single_select, multi_select. Answers use matching JSON types; multi-select is an array of strings. Omit optional unanswered keys; an empty string is not a skip. Required answers cannot be omitted.

Example respond body: {"response":{"answers":{"approach":"durable","budget":100}}}. Use the authenticated respond curl above with the IDs/types from the stored questions.

Connection interactions use payload.connect:string[] instead of questions. They require the recipient to complete account authorization; posting arbitrary answers does not bypass the server connection check.