POST /v1/messages with message_type: CONVERSATION. Only valid within an active 24-hour session opened by a user reply. To start a conversation, send a MESSAGE first — when the user replies, the platform fires a conversation.started webhook and the session window opens.
Sending CONVERSATION when no active session exists for the agent + phone number pair returns 422 no_active_session. Use MESSAGE or NEWSLETTER for all outbound-initiated sends.

Session lifecycle

1. You send MESSAGE  ──→  User sees it
2. User replies      ──→  conversation.started webhook fires; 24-hour window opens
3. You send CONVERSATION  ──→  Conversation hold placed (billed as one Conversation unit)
4. More CONVERSATION sends within 24h  ──→  free (in_session: true, hold_amount: 0)
5. 24h elapses with no reply  ──→  conversation.ended webhook fires; session closed
6. Next outbound requires MESSAGE again
1

Send a MESSAGE outbound

Use message_type: MESSAGE (text, rich card, or carousel). This is the correct way to start a conversation flow.
2

Receive conversation.started webhook

When the user replies, Arowana fires conversation.started to your registered endpoint. The payload includes the user’s reply, the agent_id, and the from number. A 24-hour session is now active for this agent + phone number pair.
3

Reply with CONVERSATION

Use message_type: CONVERSATION to send follow-ups. The first CONVERSATION send within the session places a hold at the Conversation rate. All subsequent CONVERSATION sends within the same 24-hour window carry no additional charge.
4

Session expiry

After 24 hours with no further user reply, the session closes and Arowana fires conversation.ended. The next outbound message must use MESSAGE again.

Request

Authorization
string
required
Bearer <api_key>
Idempotency-Key
string
UUID to prevent duplicate sends on retry.
{
  "agent_id": "ag_live_xxxx",
  "to": "+4917612345678",
  "message_type": "CONVERSATION",
  "content": {
    "text": "Your order will arrive between 10:00–14:00 tomorrow. Anything else we can help with?",
    "suggestions": [
      { "reply": { "text": "All good", "postback_data": "YWNr" } },
      { "reply": { "text": "Change address", "postback_data": "Y2hhbmdlX2FkZHI=" } }
    ]
  },
  "traffic_type": "TRANSACTION"
}
agent_id
string
required
Approved production agent ID.
to
string
required
Destination phone number in international format. Must have an active session open.
message_type
string
required
Must be CONVERSATION.
content
object
required
Supports the same content shapes as RCS text and RCS rich card: plain text, text with suggestions, standalone rich card, or carousel.
traffic_type
string
required
Regulatory classification. Must match the agent’s approved use_case. Conversation sessions are typically TRANSACTION or SERVICEREQUEST.

Response

First CONVERSATION send after the user opened the session. A Conversation hold is placed — this is the billing event for the whole session.
{
  "message_id": "msg_conv_a1b2c3",
  "status": "queued",
  "created_at": "2026-03-28T09:05:00Z",
  "billing": {
    "channel": "RCS",
    "message_type": "conversation",
    "in_session": true,
    "hold_amount": 0.25,
    "message_price": 0.25,
    "balance": {
      "free": 49.75,
      "reserved": 0.25,
      "total": 50.00
    },
    "tier": {
      "channel": "RCS",
      "current": "tier_1",
      "volume_used": 312
    }
  }
}
billing.in_session
boolean
true — an active session exists for this agent + phone pair.
billing.hold_amount
number
Balance held for the Conversation unit. Released or charged when the session resolves.
  • Receive replies — handle conversation.started webhook and open a session
  • RCS text — use MESSAGE to initiate the conversation flow
  • Billing (RCS) — Conversation vs Basic/Single pricing