Returns the full record for a single message — content, current status, delivery timestamps, and the step-by-step event timeline. Works for both outbound sends and inbound user replies.
Request
The message ID returned in the send response or from GET /v1/messages.
Response
200 — Outbound RCS
200 — Inbound reply
200 — Failed outbound
404 Not Found
{
"id" : "msg_a1b2c3d4" ,
"direction" : "OUTBOUND" ,
"channel_id" : "ch_rcs_xxxx" ,
"contact_id" : "c_a1b2c3d4" ,
"campaign_id" : null ,
"message_type" : "MESSAGE" ,
"content_type" : "INTERACTIVE" ,
"content" : {
"rich_card" : {
"standalone" : {
"title" : "Summer Sale — 50% off" ,
"description" : "Shop this weekend only." ,
"media" : { "url" : "https://cdn.arowana.app/summer-sale.jpg" }
}
}
},
"status" : "READ" ,
"cost" : "0.0800" ,
"error_code" : null ,
"error_message" : null ,
"sent_at" : "2026-03-28T09:00:01Z" ,
"delivered_at" : "2026-03-28T09:00:04Z" ,
"read_at" : "2026-03-28T09:03:22Z" ,
"created_at" : "2026-03-28T09:00:00Z" ,
"events" : [
{ "type" : "queued" , "at" : "2026-03-28T09:00:00Z" },
{ "type" : "sent" , "at" : "2026-03-28T09:00:01Z" },
{ "type" : "delivered" , "at" : "2026-03-28T09:00:04Z" },
{ "type" : "read" , "at" : "2026-03-28T09:03:22Z" }
]
}
Inbound messages have direction: INBOUND, no cost, and a pre-populated content from the user. {
"id" : "msg_b2c3d4e5" ,
"direction" : "INBOUND" ,
"channel_id" : "ch_rcs_xxxx" ,
"contact_id" : "c_a1b2c3d4" ,
"campaign_id" : null ,
"message_type" : "CONVERSATION" ,
"content_type" : "TEXT" ,
"content" : {
"text" : "Where is my order?"
},
"status" : "DELIVERED" ,
"cost" : null ,
"sent_at" : "2026-03-28T09:05:10Z" ,
"delivered_at" : "2026-03-28T09:05:10Z" ,
"read_at" : null ,
"created_at" : "2026-03-28T09:05:10Z" ,
"events" : [
{ "type" : "received" , "at" : "2026-03-28T09:05:10Z" },
{ "type" : "delivered" , "at" : "2026-03-28T09:05:10Z" }
]
}
Failed messages include error_code and error_message. {
"id" : "msg_c3d4e5f6" ,
"direction" : "OUTBOUND" ,
"channel_id" : "ch_rcs_xxxx" ,
"contact_id" : "c_b2c3d4e5" ,
"status" : "FAILED" ,
"cost" : null ,
"error_code" : "UNKNOWN_RCS_USER" ,
"error_message" : "The recipient is not reachable via RCS." ,
"sent_at" : "2026-03-28T09:00:01Z" ,
"delivered_at" : null ,
"read_at" : null ,
"created_at" : "2026-03-28T09:00:00Z" ,
"events" : [
{ "type" : "queued" , "at" : "2026-03-28T09:00:00Z" },
{ "type" : "sent" , "at" : "2026-03-28T09:00:01Z" },
{ "type" : "failed" , "at" : "2026-03-28T09:00:02Z" }
]
}
{ "error" : "not_found" , "message" : "Message not found." }
Response fields
Unique message identifier.
OUTBOUND (sent to a user) or INBOUND (received from a user).
The channel the message was sent on or received from.
The contact associated with this message.
Set if the message was dispatched by a campaign. null for API sends.
Shape of content: TEXT, TEMPLATE, MEDIA, or INTERACTIVE.
Full message content as originally sent (or received for inbound). Shape matches the content field in POST /v1/messages.
Settled cost in EUR as a decimal string (e.g. "0.0800"). null for inbound messages and messages that failed before billing. Returned as a string to preserve decimal precision — unlike the numeric hold_amount / message_price fields in the send response.
Machine-readable failure code. null for successful or in-progress messages.
Ordered timeline of status transitions. Each entry has type (the status reached) and at (ISO 8601 timestamp).
Example
curl "https://api.arowana.app/v1/messages/msg_a1b2c3d4" \
-H "Authorization: Bearer $API_KEY "
List messages Filter and paginate across all messages in your workspace.
Revoke message Cancel a queued message before it is delivered.