# Conversations API v1 Quick Start

Send your first customer conversation to Onlo and find it in Inbox.

- **Audience:** Teams that want to send customer conversations from their app to Onlo Inbox
- **Intent:** Build with Onlo
- **Version:** API v1
- **Active work:** 10 minutes
- **Where this happens:** You need a full-access Onlo API key.

Canonical page: https://onlo.ai/docs/developers/conversations-api/quick-start

## Before you start

- **Plan:** Onlo Starter or above
- **Access:** Sign in as an Owner or Admin
- **API tool:** Use Postman, curl, or another API client

## How to send your first conversation

Use the Conversations API to send customer conversations from your app to Onlo, so your team can handle them in Inbox.

1. **Create your API token.**
   If you do not have an API key, [click here](https://onlo.ai/dashboard/integrations/api).
   1. Click `Create key`.
   1. Set `Name` to `Testing` and `Scope` to `Full — read + write`.
   1. Click `Create key`, then copy the token immediately.
   ![Onlo API keys screen with Create key, Full scope, masked token, Rotate, and Delete highlighted](https://onlo.ai/docs/conversations-api/quick-start/01-generate-api-key-annotated.png)
   *Create a key named Testing with Full — read + write access.*
   > **Important:** Copy the token now. Onlo shows it only once.
2. **Test connection.** This proves your API key can connect to Onlo with Full access.
   - **Method:** `GET`
   - **URL:** `https://onlo.ai/api/v1/ping`
   - **Postman authorization:** Select `Bearer Token`, then paste your API key.
   - **Headers:**
     - `Content-Type` → `application/json`
   - **cURL:**
   ```shell
   curl --request GET 'https://onlo.ai/api/v1/ping' \
     --header 'Authorization: Bearer YOUR_API_KEY' \
     --header 'Content-Type: application/json'
   ```
   For API key and security details, [click here](https://onlo.ai/docs/developers/conversations-api/authentication).
   - **Expected status:** `200 OK`
   - **type:** ping — this is the connection-test response
   - **scope:** full — this key can read and write
   - **server_time:** The current Onlo server time in Unix seconds, recorded when it answered this ping. It is not a conversation creation time.
   Your organization_id will be different. server_time changes on every request.
   <details>
   <summary>Full response</summary>

   ```json
   {
     "type": "ping",
     "organization_id": "...",
     "scope": "full",
     "server_time": 1788323400
   }
   ```
   </details>
   - **Next:** Keep the same API key. You will use it to create the conversation.
3. **Create a conversation.** This creates one test conversation for Maya, asks Onlo to answer the first customer message, and stores four conversation attributes.
   - **Method:** `POST`
   - **URL:** `https://onlo.ai/api/v1/conversations`
   - **Postman authorization:** Select `Bearer Token`, then paste your API key.
   - **Headers:**
     - `Content-Type` → `application/json`
   - **Fields used here:**
     - `external_id` — **Required:** Your unique ID for this conversation in your system. Reuse it if you retry.
     - `body` — **Optional:** The first customer message. Onlo answers it using the workspace’s normal settings. Omit it when you only need an empty conversation record.
     - `from` — **Required:** The customer attached to this conversation.
     - `from.external_id or from.id` — **Required:** Your unique ID for this customer, or an existing Onlo contact ID. Use only one.
     - `from.type` — **Optional:** Use contact. The API also accepts user, lead, and customer.
     - `from.name / from.email / from.phone` — **Optional:** Customer details your team can recognize in Inbox.
     - `custom_attributes` — **Optional:** Flat string, number, or true-or-false values stored on this conversation, not on the contact.
   You send `external_id`. Onlo returns `id`. Use the returned `id` in the Get and Update URLs.
   - **Body:** Body → raw → JSON
   ```json
   {
     "external_id": "support_case_1048",
     "from": {
       "type": "contact",
       "external_id": "customer_4821",
       "name": "Maya Patel",
       "email": "maya.patel@example.com"
     },
     "custom_attributes": {
       "order": "ORD-1001",
       "reason": "It's something else",
       "attempts": 2,
       "paid": false
     },
     "body": "I need help with my order."
   }
   ```
   - **cURL:**
   ```shell
   curl --request POST 'https://onlo.ai/api/v1/conversations' \
     --header 'Authorization: Bearer YOUR_API_KEY' \
     --header 'Content-Type: application/json' \
     --data-binary @- <<'JSON'
   {
     "external_id": "support_case_1048",
     "from": {
       "type": "contact",
       "external_id": "customer_4821",
       "name": "Maya Patel",
       "email": "maya.patel@example.com"
     },
     "custom_attributes": {
       "order": "ORD-1001",
       "reason": "It's something else",
       "attempts": 2,
       "paid": false
     },
     "body": "I need help with my order."
   }
   JSON
   ```
   For every supported create field, [click here](https://onlo.ai/docs/developers/conversations-api/reference#create).
   - **Expected status:** `201 Created`
   - **type:** conversation — this endpoint returned a conversation resource
   - **id:** Copy this conversation ID. Onlo generated it for Steps 4 and 5.
   - **message_count:** 2 in this example — the customer message and Onlo’s reply
   - **reply:** Onlo’s immediate response to the first customer message
   - **custom_attributes:** order, reason, attempts, paid
   Onlo returns your own conversation and contact IDs. This example hides them as "...".
   <details>
   <summary>Full response</summary>

   ```json
   {
     "type": "conversation",
     "id": "...",
     "external_id": "support_case_1048",
     "created_at": 1788323400,
     "updated_at": 1788323400,
     "channel": "api",
     "source": { "type": "api" },
     "state": "open",
     "open": true,
     "status": "active",
     "custom_attributes": {
       "order": "ORD-1001",
       "reason": "It's something else",
       "attempts": 2,
       "paid": false
     },
     "message_count": 2,
     "last_message_at": 1788323400,
     "contact": {
       "type": "contact",
       "id": "...",
       "external_id": "customer_4821",
       "name": "Maya Patel",
       "email": "maya.patel@example.com",
       "phone": null
     },
     "contacts": {
       "type": "contact.list",
       "contacts": [
         {
           "type": "contact",
           "id": "...",
           "external_id": "customer_4821"
         }
       ]
     },
     "reply": {
       "type": "message",
       "id": "...",
       "body": "I can help with that order. What seems to be wrong?",
       "created_at": 1788323401
     }
   }
   ```
   </details>
   - **Next:** Copy the returned id. You will paste that conversation ID into Steps 4 and 5.
4. **Get the conversation.** This proves Onlo saved the conversation and its attributes unchanged.
   - **Method:** `GET`
   - **URL:** `https://onlo.ai/api/v1/conversations/<conversation_id>` — Replace <conversation_id> with the id you copied in Step 3.
   - **Postman authorization:** Select `Bearer Token`, then paste your API key.
   - **Headers:**
     - `Content-Type` → `application/json`
   - **Fields used here:**
     - `conversation_id` — **Required:** The id returned by Onlo in Step 3.
   - **cURL:**
   ```shell
   curl --request GET 'https://onlo.ai/api/v1/conversations/CONVERSATION_ID_FROM_STEP_3' \
     --header 'Authorization: Bearer YOUR_API_KEY' \
     --header 'Content-Type: application/json'
   ```
   For full Get details, [click here](https://onlo.ai/docs/developers/conversations-api/reference#get).
   - **Expected status:** `200 OK`
   - **id:** The same id returned in Step 3
   - **order:** ORD-1001
   - **reason:** It's something else
   - **attempts / paid:** 2 / false
   The custom attributes should match the create response exactly.
   <details>
   <summary>Full response</summary>

   ```json
   {
     "type": "conversation",
     "id": "...",
     "external_id": "support_case_1048",
     "created_at": 1788323400,
     "updated_at": 1788323400,
     "channel": "api",
     "source": { "type": "api" },
     "state": "open",
     "open": true,
     "status": "active",
     "custom_attributes": {
       "order": "ORD-1001",
       "reason": "It's something else",
       "attempts": 2,
       "paid": false
     },
     "message_count": 2,
     "last_message_at": 1788323400,
     "contact": {
       "type": "contact",
       "id": "...",
       "external_id": "customer_4821",
       "name": "Maya Patel",
       "email": "maya.patel@example.com",
       "phone": null
     },
     "contacts": {
       "type": "contact.list",
       "contacts": [
         {
           "type": "contact",
           "id": "...",
           "external_id": "customer_4821"
         }
       ]
     },
     "reply": {
       "type": "message",
       "id": "...",
       "body": "I can help with that order. What seems to be wrong?",
       "created_at": 1788323401
     }
   }
   ```
   </details>
   - **Next:** Keep the same conversation ID. You will update this conversation next.
5. **Update the conversation.** This changes attempts to 3 and removes reason by sending null.
   - **Method:** `PUT`
   - **URL:** `https://onlo.ai/api/v1/conversations/<conversation_id>` — Replace <conversation_id> with the id you copied in Step 3.
   - **Postman authorization:** Select `Bearer Token`, then paste your API key.
   - **Headers:**
     - `Content-Type` → `application/json`
   - **Fields used here:**
     - `conversation_id` — **Required:** The id returned by Onlo in Step 3.
     - `custom_attributes` — **Required:** Only the attributes you want to change or remove.
     - `attempts` — **Optional:** Sending 3 replaces the previous value of 2.
     - `reason` — **Optional:** Sending null removes this attribute.
   - **Body:** Body → raw → JSON
   ```json
   {
     "custom_attributes": {
       "attempts": 3,
       "reason": null
     }
   }
   ```
   - **cURL:**
   ```shell
   curl --request PUT 'https://onlo.ai/api/v1/conversations/CONVERSATION_ID_FROM_STEP_3' \
     --header 'Authorization: Bearer YOUR_API_KEY' \
     --header 'Content-Type: application/json' \
     --data-binary @- <<'JSON'
   {
     "custom_attributes": {
       "attempts": 3,
       "reason": null
     }
   }
   JSON
   ```
   For full Update details, [click here](https://onlo.ai/docs/developers/conversations-api/reference#update).
   - **Expected status:** `200 OK`
   - **attempts:** 3
   - **reason:** Removed
   - **order / paid:** ORD-1001 / false (unchanged)
   Omitted attributes stay unchanged. An attribute sent as null is removed.
   <details>
   <summary>Full response</summary>

   ```json
   {
     "type": "conversation",
     "id": "...",
     "external_id": "support_case_1048",
     "created_at": 1788323400,
     "updated_at": 1788323460,
     "channel": "api",
     "source": { "type": "api" },
     "state": "open",
     "open": true,
     "status": "active",
     "custom_attributes": {
       "order": "ORD-1001",
       "attempts": 3,
       "paid": false
     },
     "message_count": 2,
     "last_message_at": 1788323400,
     "contact": {
       "type": "contact",
       "id": "...",
       "external_id": "customer_4821",
       "name": "Maya Patel",
       "email": "maya.patel@example.com",
       "phone": null
     },
     "contacts": {
       "type": "contact.list",
       "contacts": [
         {
           "type": "contact",
           "id": "...",
           "external_id": "customer_4821"
         }
       ]
     }
   }
   ```
   </details>
   - **Next:** Keep customer_4821 and ORD-1001. You will use both to find this conversation.
6. **Find the conversation.** This searches for Maya’s test conversation using the same customer and order values.
   - **Method:** `POST`
   - **URL:** `https://onlo.ai/api/v1/conversations/search`
   - **Postman authorization:** Select `Bearer Token`, then paste your API key.
   - **Headers:**
     - `Content-Type` → `application/json`
   - **Fields used here:**
     - `query` — **Required:** The filters Onlo should match.
     - `contact.external_id` — **Required:** Limits the search to customer_4821.
     - `custom_attributes.order` — **Optional:** Narrows the result to order ORD-1001.
     - `pagination` — **Optional:** Controls how many matching conversations Onlo returns.
   - **Body:** Body → raw → JSON
   ```json
   {
     "query": {
       "operator": "AND",
       "value": [
         {
           "field": "contact.external_id",
           "operator": "=",
           "value": "customer_4821"
         },
         {
           "field": "custom_attributes.order",
           "operator": "=",
           "value": "ORD-1001"
         }
       ]
     },
     "pagination": {
       "per_page": 50,
       "starting_after": null
     }
   }
   ```
   - **cURL:**
   ```shell
   curl --request POST 'https://onlo.ai/api/v1/conversations/search' \
     --header 'Authorization: Bearer YOUR_API_KEY' \
     --header 'Content-Type: application/json' \
     --data-binary @- <<'JSON'
   {
     "query": {
       "operator": "AND",
       "value": [
         {
           "field": "contact.external_id",
           "operator": "=",
           "value": "customer_4821"
         },
         {
           "field": "custom_attributes.order",
           "operator": "=",
           "value": "ORD-1001"
         }
       ]
     },
     "pagination": {
       "per_page": 50,
       "starting_after": null
     }
   }
   JSON
   ```
   For all search fields and operators, [click here](https://onlo.ai/docs/developers/conversations-api/reference#search).
   - **Expected status:** `200 OK`
   - **total_count:** 1
   - **conversations[0].id:** The same conversation id returned in Step 3
   The returned record contains the updated attributes from Step 5.
   <details>
   <summary>Full response</summary>

   ```json
   {
     "type": "conversation.list",
     "conversations": [
       {
         "type": "conversation",
         "id": "...",
         "external_id": "support_case_1048",
         "created_at": 1788323400,
         "updated_at": 1788323460,
         "channel": "api",
         "source": { "type": "api" },
         "state": "open",
         "open": true,
         "status": "active",
         "custom_attributes": {
           "order": "ORD-1001",
           "attempts": 3,
           "paid": false
         },
         "message_count": 2,
         "last_message_at": 1788323400,
         "contact": {
           "type": "contact",
           "id": "...",
           "external_id": "customer_4821",
           "name": "Maya Patel",
           "email": "maya.patel@example.com",
           "phone": null
         },
         "contacts": {
           "type": "contact.list",
           "contacts": [
             {
               "type": "contact",
               "id": "...",
               "external_id": "customer_4821"
             }
           ]
         }
       }
     ],
     "total_count": 1,
     "pages": {
       "type": "pages",
       "page": 1,
       "per_page": 50
     }
   }
   ```
   </details>
   - **Next:** Open Onlo Inbox and confirm the same conversation is visible to your team.
7. **Verify in Onlo.** Open Dashboard → Inbox, select Maya’s test conversation, then open This conversation → Custom attributes.
   For the complete API Reference, [click here](https://onlo.ai/docs/developers/conversations-api/reference).
   ![Focused Onlo Inbox screenshot marking the test conversation to select](https://onlo.ai/docs/conversations-api/quick-start/07-select-conversation-annotated.png)
   *Select the test conversation.*
   ![Focused Onlo sidebar screenshot marking This conversation and Custom attributes](https://onlo.ai/docs/conversations-api/quick-start/07-custom-attributes-annotated.png)
   *Open This conversation and check Custom attributes.*
   - **order:** ORD-1001
   - **attempts:** 3
   - **paid:** false
   - **reason:** Not shown because Step 5 removed it
   The screenshots are cropped and marked so you can find the two controls quickly.

### Expected result

Complete all seven steps with one API key and one test conversation.

**Success:** Your Conversations API setup is working.

**If you do not see this:**

- Ping failed: confirm the key is Full access and the Authorization value begins with Bearer followed by one space.
- Get or update failed: paste the exact id returned by Step 3 into the URL.
- Search returned nothing: confirm the request uses customer_4821 and ORD-1001.

## Next

- [Conversations API reference](https://onlo.ai/docs/developers/conversations-api/reference): Every endpoint, request field, response field, limit, and error code for the Conversations REST API.

## Related pages

- [Conversations API](https://onlo.ai/docs/developers/conversations-api): Create a conversation for one of your users from your own backend, receive its durable Onlo id, set conversation attributes, and search that user’s conversations over REST.
- [Authentication and API keys](https://onlo.ai/docs/developers/conversations-api/authentication): Create the right key scope, send it correctly, rotate it without downtime, and read each authentication failure.
- [Conversations API reference](https://onlo.ai/docs/developers/conversations-api/reference): Every endpoint, request field, response field, limit, and error code for the Conversations REST API.
