Crear un ticket
curl --request POST \
--url https://api.keebai.com/v1/crm/tickets \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"chat_user": "<string>",
"chat_user_name": "<string>",
"chat_user_avatar": "<string>",
"chat_user_channel": "<string>",
"chat_user_channel_id": "<string>",
"priority": "medium",
"category": "<string>",
"assigned_to": "<string>",
"custom_fields": {},
"amount": 123,
"amount_currency": "<string>",
"stage": "<string>"
}
'import requests
url = "https://api.keebai.com/v1/crm/tickets"
payload = {
"chat_user": "<string>",
"chat_user_name": "<string>",
"chat_user_avatar": "<string>",
"chat_user_channel": "<string>",
"chat_user_channel_id": "<string>",
"priority": "medium",
"category": "<string>",
"assigned_to": "<string>",
"custom_fields": {},
"amount": 123,
"amount_currency": "<string>",
"stage": "<string>"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
chat_user: '<string>',
chat_user_name: '<string>',
chat_user_avatar: '<string>',
chat_user_channel: '<string>',
chat_user_channel_id: '<string>',
priority: 'medium',
category: '<string>',
assigned_to: '<string>',
custom_fields: {},
amount: 123,
amount_currency: '<string>',
stage: '<string>'
})
};
fetch('https://api.keebai.com/v1/crm/tickets', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.keebai.com/v1/crm/tickets",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'chat_user' => '<string>',
'chat_user_name' => '<string>',
'chat_user_avatar' => '<string>',
'chat_user_channel' => '<string>',
'chat_user_channel_id' => '<string>',
'priority' => 'medium',
'category' => '<string>',
'assigned_to' => '<string>',
'custom_fields' => [
],
'amount' => 123,
'amount_currency' => '<string>',
'stage' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.keebai.com/v1/crm/tickets"
payload := strings.NewReader("{\n \"chat_user\": \"<string>\",\n \"chat_user_name\": \"<string>\",\n \"chat_user_avatar\": \"<string>\",\n \"chat_user_channel\": \"<string>\",\n \"chat_user_channel_id\": \"<string>\",\n \"priority\": \"medium\",\n \"category\": \"<string>\",\n \"assigned_to\": \"<string>\",\n \"custom_fields\": {},\n \"amount\": 123,\n \"amount_currency\": \"<string>\",\n \"stage\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.keebai.com/v1/crm/tickets")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"chat_user\": \"<string>\",\n \"chat_user_name\": \"<string>\",\n \"chat_user_avatar\": \"<string>\",\n \"chat_user_channel\": \"<string>\",\n \"chat_user_channel_id\": \"<string>\",\n \"priority\": \"medium\",\n \"category\": \"<string>\",\n \"assigned_to\": \"<string>\",\n \"custom_fields\": {},\n \"amount\": 123,\n \"amount_currency\": \"<string>\",\n \"stage\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.keebai.com/v1/crm/tickets")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"chat_user\": \"<string>\",\n \"chat_user_name\": \"<string>\",\n \"chat_user_avatar\": \"<string>\",\n \"chat_user_channel\": \"<string>\",\n \"chat_user_channel_id\": \"<string>\",\n \"priority\": \"medium\",\n \"category\": \"<string>\",\n \"assigned_to\": \"<string>\",\n \"custom_fields\": {},\n \"amount\": 123,\n \"amount_currency\": \"<string>\",\n \"stage\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"ticket": {
"_id": "<string>",
"chat_user": "<string>",
"is_closed": true,
"tags": [
{
"id": "<string>",
"name": "<string>",
"color": "<string>"
}
],
"custom_fields": {},
"created_at": "2023-11-07T05:31:56Z",
"updated_at": "2023-11-07T05:31:56Z",
"chat_user_name": "<string>",
"chat_user_avatar": "<string>",
"chat_user_channel": "<string>",
"chat_user_channel_id": "<string>",
"stage": {
"stage_id": "<string>",
"prioridad": "<string>",
"contexto": "<string>",
"problema": "<string>",
"recomendaciones": "<string>"
},
"category": "<string>",
"assigned_to": {
"id": "<string>",
"full_name": "<string>",
"email": "<string>"
},
"amount": 123,
"amount_currency": "<string>",
"conversation_summary": {
"motivo": "<string>",
"estado": "<string>",
"proximos_pasos": "<string>",
"is_final": true
},
"ai_feedback_status": "<string>",
"appointment_ids": [
"<string>"
],
"last_message": {
"id": "<string>",
"content": "<string>",
"role": "<string>",
"direction": "<string>",
"created_at": "2023-11-07T05:31:56Z"
},
"closed_at": "2023-11-07T05:31:56Z"
}
}Tickets
POST /v1/crm/tickets
Open a ticket for a contact. Company and project come from the token; Keebai generates the id.
POST
/
v1
/
crm
/
tickets
Crear un ticket
curl --request POST \
--url https://api.keebai.com/v1/crm/tickets \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"chat_user": "<string>",
"chat_user_name": "<string>",
"chat_user_avatar": "<string>",
"chat_user_channel": "<string>",
"chat_user_channel_id": "<string>",
"priority": "medium",
"category": "<string>",
"assigned_to": "<string>",
"custom_fields": {},
"amount": 123,
"amount_currency": "<string>",
"stage": "<string>"
}
'import requests
url = "https://api.keebai.com/v1/crm/tickets"
payload = {
"chat_user": "<string>",
"chat_user_name": "<string>",
"chat_user_avatar": "<string>",
"chat_user_channel": "<string>",
"chat_user_channel_id": "<string>",
"priority": "medium",
"category": "<string>",
"assigned_to": "<string>",
"custom_fields": {},
"amount": 123,
"amount_currency": "<string>",
"stage": "<string>"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
chat_user: '<string>',
chat_user_name: '<string>',
chat_user_avatar: '<string>',
chat_user_channel: '<string>',
chat_user_channel_id: '<string>',
priority: 'medium',
category: '<string>',
assigned_to: '<string>',
custom_fields: {},
amount: 123,
amount_currency: '<string>',
stage: '<string>'
})
};
fetch('https://api.keebai.com/v1/crm/tickets', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.keebai.com/v1/crm/tickets",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'chat_user' => '<string>',
'chat_user_name' => '<string>',
'chat_user_avatar' => '<string>',
'chat_user_channel' => '<string>',
'chat_user_channel_id' => '<string>',
'priority' => 'medium',
'category' => '<string>',
'assigned_to' => '<string>',
'custom_fields' => [
],
'amount' => 123,
'amount_currency' => '<string>',
'stage' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.keebai.com/v1/crm/tickets"
payload := strings.NewReader("{\n \"chat_user\": \"<string>\",\n \"chat_user_name\": \"<string>\",\n \"chat_user_avatar\": \"<string>\",\n \"chat_user_channel\": \"<string>\",\n \"chat_user_channel_id\": \"<string>\",\n \"priority\": \"medium\",\n \"category\": \"<string>\",\n \"assigned_to\": \"<string>\",\n \"custom_fields\": {},\n \"amount\": 123,\n \"amount_currency\": \"<string>\",\n \"stage\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.keebai.com/v1/crm/tickets")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"chat_user\": \"<string>\",\n \"chat_user_name\": \"<string>\",\n \"chat_user_avatar\": \"<string>\",\n \"chat_user_channel\": \"<string>\",\n \"chat_user_channel_id\": \"<string>\",\n \"priority\": \"medium\",\n \"category\": \"<string>\",\n \"assigned_to\": \"<string>\",\n \"custom_fields\": {},\n \"amount\": 123,\n \"amount_currency\": \"<string>\",\n \"stage\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.keebai.com/v1/crm/tickets")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"chat_user\": \"<string>\",\n \"chat_user_name\": \"<string>\",\n \"chat_user_avatar\": \"<string>\",\n \"chat_user_channel\": \"<string>\",\n \"chat_user_channel_id\": \"<string>\",\n \"priority\": \"medium\",\n \"category\": \"<string>\",\n \"assigned_to\": \"<string>\",\n \"custom_fields\": {},\n \"amount\": 123,\n \"amount_currency\": \"<string>\",\n \"stage\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"ticket": {
"_id": "<string>",
"chat_user": "<string>",
"is_closed": true,
"tags": [
{
"id": "<string>",
"name": "<string>",
"color": "<string>"
}
],
"custom_fields": {},
"created_at": "2023-11-07T05:31:56Z",
"updated_at": "2023-11-07T05:31:56Z",
"chat_user_name": "<string>",
"chat_user_avatar": "<string>",
"chat_user_channel": "<string>",
"chat_user_channel_id": "<string>",
"stage": {
"stage_id": "<string>",
"prioridad": "<string>",
"contexto": "<string>",
"problema": "<string>",
"recomendaciones": "<string>"
},
"category": "<string>",
"assigned_to": {
"id": "<string>",
"full_name": "<string>",
"email": "<string>"
},
"amount": 123,
"amount_currency": "<string>",
"conversation_summary": {
"motivo": "<string>",
"estado": "<string>",
"proximos_pasos": "<string>",
"is_final": true
},
"ai_feedback_status": "<string>",
"appointment_ids": [
"<string>"
],
"last_message": {
"id": "<string>",
"content": "<string>",
"role": "<string>",
"direction": "<string>",
"created_at": "2023-11-07T05:31:56Z"
},
"closed_at": "2023-11-07T05:31:56Z"
}
}Creates a ticket — a case, deal, or conversation you want to track through a pipeline. The only mandatory field is
chat_user: the contact the ticket belongs to.
The company and project are taken from your token and must not appear in the body. Sending them returns 400.
A ticket is anchored to a chat user, not to a customer. The chat user is the contact record Keebai creates when someone writes to one of your channels. Get its id from an inbound message webhook or from the portal.
Endpoint
POST https://api.keebai.com/v1/crm/tickets
Required scope
crm:tickets:write
Headers
| Header | Required | Value |
|---|---|---|
Authorization | Yes | Bearer kbai_pk_<token> |
Content-Type | Yes | application/json |
Body
| Field | Type | Required | Description |
|---|---|---|---|
chat_user | string | Yes | ObjectId of the contact the ticket belongs to. |
chat_user_name | string | No | Display name, denormalized onto the ticket. |
chat_user_avatar | string | No | Avatar URL, denormalized onto the ticket. |
chat_user_channel | string | No | Origin channel, e.g. whatsapp, instagram. |
chat_user_channel_id | string | No | ObjectId of the specific channel. |
stage | string | No | ObjectId of the pipeline stage to open the ticket in. |
priority | string | No | One of low, medium, high, urgent. Defaults to medium. |
category | string | No | Free-text category. |
assigned_to | string | No | ObjectId of the user who owns the ticket. |
custom_fields | object | No | Free-form object matching your company’s custom fields. |
amount | number | No | Monetary value of the opportunity. |
amount_currency | string | No | ISO 4217 currency, e.g. CLP, USD. |
amount_status | string | No | estimated or confirmed. |
Example request
curl -X POST https://api.keebai.com/v1/crm/tickets \
-H "Authorization: Bearer kbai_pk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"chat_user": "66c1d2e3f4a5b6c7d8e9f0a1",
"chat_user_name": "Juan Pérez",
"chat_user_channel": "whatsapp",
"stage": "67d1e2f3a4b5c6d7e8f9a0b1",
"priority": "high",
"category": "soporte",
"amount": 150000,
"amount_currency": "CLP",
"amount_status": "estimated"
}'
const response = await fetch("https://api.keebai.com/v1/crm/tickets", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.KEEBAI_API_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
chat_user: chatUserId,
chat_user_name: "Juan Pérez",
chat_user_channel: "whatsapp",
stage: stageId,
priority: "high",
}),
});
const { ticket } = await response.json();
import os, requests
resp = requests.post(
"https://api.keebai.com/v1/crm/tickets",
headers={"Authorization": f"Bearer {os.environ['KEEBAI_API_TOKEN']}"},
json={
"chat_user": chat_user_id,
"chat_user_name": "Juan Pérez",
"chat_user_channel": "whatsapp",
"stage": stage_id,
"priority": "high",
},
timeout=10,
)
resp.raise_for_status()
ticket = resp.json()["ticket"]
Response
201 Created
{
"ticket": {
"_id": "65f4b5c6d7e8f9a0b1c2d3e4",
"chat_user": "66c1d2e3f4a5b6c7d8e9f0a1",
"chat_user_name": "Juan Pérez",
"chat_user_channel": "whatsapp",
"stage": "67d1e2f3a4b5c6d7e8f9a0b1",
"is_closed": false,
"priority": "high",
"category": "soporte",
"custom_fields": {},
"amount": 150000,
"amount_currency": "CLP",
"amount_status": "estimated",
"created_at": "2026-05-02T14:31:07.221Z",
"updated_at": "2026-05-02T14:31:07.221Z"
},
"stage_requested": "67d1e2f3a4b5c6d7e8f9a0b1"
}
stage_requested echoes back the stage you asked for, and is present only when you sent one.
400 Bad Request
Missingchat_user, an id that is not a valid ObjectId, a priority outside the allowed set, or a property the endpoint does not accept — including company and project, which are derived from the token.
401 Unauthorized
Missing, invalid, revoked, or expired token.403 Forbidden
The token does not have thecrm:tickets:write scope.
Operational notes
- No stage is assigned by default. If you omit
stage, the ticket is created without one and will not appear in a pipeline board until you move it withPOST /v1/crm/tickets/:id/stage. - Tickets open as
is_closed: false. Close one by sending{"is_closed": true, "resolution": "won"}toPATCH /v1/crm/tickets/:id. - Nothing deduplicates by contact. Two
POSTs for the samechat_usercreate two tickets. Check for an existing open ticket first if that is not what you want.
Authorizations
Personal Access Token con prefijo kbai_pk_. Generar desde el portal con permiso developer.manage_tokens.
Body
application/json
Id del chat user (contacto) dueño del ticket
Canal de origen (whatsapp, instagram…)
Available options:
low, medium, high, urgent Id del usuario asignado
Valor monetario de la oportunidad
Moneda ISO 4217
Available options:
estimated, confirmed Etapa del pipeline. Si se omite, el ticket queda sin etapa asignada.
Response
201 - application/json
Show child attributes
Show child attributes
Was this page helpful?
⌘I