asssistive

Start a conversation

Open a conversation on behalf of one of your users, record their first message, and mint the visitor token for it.

POST /api/v1/public/conversations

Opens a conversation on behalf of an end user, records their first message, and mints the visitor token that authorizes every later read and write on that conversation.

This is the only Public API endpoint that creates a conversation, and the only one that ever returns a visitor token.

Authentication

Publishable key: Authorization: Bearer pk_….

A secret key (sk_) is rejected here, exactly as an unknown or revoked key is — see Authentication.

Request body

FieldTypeRequiredDescription
messagestringyesThe user's first message.
external_idstringnoYour own stable ID for this user. Strongly recommended — see Identity resolution below.
namestringnoDisplay name. Defaults to Visitor when blank.
emailstringnoMust be a valid email address if provided.
{
  "external_id": "app-user-8471",
  "name": "Ama",
  "email": "[email protected]",
  "message": "My order never arrived."
}

Response

201 Created.

data carries the new conversation_id, the visitor_token, and the message you just recorded.

{
  "success": true,
  "request_id": "6d7979ce52075b24979cd5b415319339",
  "data": {
    "conversation_id": "019f1c4d-6e7f-7a80-91b2-c3d4e5f60718",
    "visitor_token": "vt_example_7Jq4Xm2Pz9Ln6Rd3Wb5T",
    "message": {
      "id": "019f1c50-1111-7a80-91b2-c3d4e5f60718",
      "author": "customer",
      "body": "My order never arrived.",
      "created_at": "2026-07-11T10:00:00.000000Z"
    }
  }
}

The visitor token is returned once

visitor_token appears in this response and nowhere else. It is stored only as a hash, so it cannot be looked up, listed, or re-sent. If you lose it, the only recovery is to start a new conversation — which gives the user a new, empty thread. Persist it server-side, against the user it belongs to, before you do anything else with the response.

The token expires after 30 days of disuse, on a sliding window that every read and post pushes forward — and an agent can revoke it from the dashboard. There's no refresh flow: if it stops working, you call this endpoint again to get a new one. See Lifetime.

Identity resolution

Every call resolves which customer record the conversation belongs to, in this exact order:

  1. external_id is given and matches an existing customer in your organization → reuse that customer.
  2. Otherwise email is given and matches an existing customer → reuse that customer.
  3. Otherwise → create a new customer.

The practical consequence: pass external_id if you want a returning user to stay linked to one customer record. Because your stable ID is checked first, a user who later changes their name or email in your app still maps to the same Assistive customer, and the agent sees one continuous history. Send only name/email — or nothing — and you risk fragmenting one human across many customer records, each with a slice of their history.

Routing happens on creation

Conversations started here are recorded on the api channel, and your organization's auto-routing rules run as the conversation is created. A rule may assign the conversation to a team, and that decision is written to the conversation timeline and the audit trail.

You neither control nor observe this from the API — it's simply why a conversation may already belong to a team by the time an agent opens it. (Only team routing applies to a conversation; priority and tag rules are ticket concerns and do nothing here.)

Errors

Statuserror.codeWhen
401UNAUTHORIZEDThe key is missing, unknown, revoked, or is an sk_ key.
422VALIDATION_ERRORmessage is absent, or email isn't a valid address. See error.details.
429RATE_LIMITEDYour organization's publishable-key budget is exhausted.
{
  "success": false,
  "request_id": "6d7979ce52075b24979cd5b415319339",
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "the request contains invalid fields",
    "details": [{ "field": "message", "message": "message is required" }]
  }
}

Examples

curl -X POST "{BASE_URL}/api/v1/public/conversations" \
  -H "Authorization: Bearer pk_example_k3Yb9wQ2rTfA8sLdN1vH" \
  -H "Content-Type: application/json" \
  -d '{
    "external_id": "app-user-8471",
    "name": "Ama",
    "email": "[email protected]",
    "message": "My order never arrived."
  }'

On this page