GET /api/v2/conversations/{conversation_id}/messages with messages:read to read public messages. Each resource has a msg_ ID, direction, actor, typed content parts, timestamps, and delivery status. Internal notes use a separate endpoint and separate permissions.messages:write, call POST /api/v2/conversations/{conversation_id}/messages. Include the conversation's current ownership version:12345{ "content": [{ "type": "text", "text": "Hello from Ruut." }], "expected_owner_version": 0, "external_id": "message-123" }
0 with the version returned by GET /api/v2/conversations/{conversation_id}. For a text-and-media message, include a typed media part with an uploaded media_id. See media uploads.reply_to_message_id to quote an existing public message in the same conversation. Providers render quoted replies according to their capabilities.123456789{ "content": [{ "type": "template", "name": "status_update", "language": "en", "variables": { "1": "Ready" } }], "expected_owner_version": 0 }
202 with an acceptance snapshot and a polling location. Use GET /api/v2/messages/{message_id} or signed message events to observe progress. Reuse the same idempotency key and body after a timeout. See delivery and retries for handling unknown outcomes.