Integración de Meta e Instagram API
Referencia para crear una aplicación de Instagram en la Plataforma SMSBAT ChatHub: autenticación, Conversaciones de Instagram Direct, comentarios en publicaciones y Reels, respuestas a historias, webhooks y encuestas.
Fuentes
Esta página fusiona la especificación interna de la API de metacomentarios con la OpenAPI activa.
definiciones en https://chatapi.smsbat.com/swagger/v1/swagger.json y
https://restapi.smsbat.com/swagger/v1/swagger.json. Cuando los dos no están de acuerdo, el
La diferencia se indica en línea y se enumera en Preguntas abiertas.
1. URL base
| Propósito | URL |
|---|---|
| API de chat + Meta API | https://chatapi.smsbat.com |
| Interfaz de usuario Swagger / OpenAPI | https://chatapi.smsbat.com/index.html · …/swagger/v1/swagger.json |
| API REST (organizaciones, URL de devolución de llamada) | https://restapi.smsbat.com |
| Arrogancia de API REST | https://restapi.smsbat.com/swagger/v1/swagger.json |
| Panel web del operador | https://chat.smsbat.com |
2. Autenticación
El esquema de autenticación depende del grupo de puntos finales. Mezclarlos es la causa más común de 401.
| Grupo | Encabezado |
|---|---|
chatapi.smsbat.com/api/meta/* (publicaciones, comentarios) | X-Authorization-Key: <organization token> |
chatapi.smsbat.com/api/chat/*, /api/company/*, /api/operator/* | Authorization: Bearer <JWT> |
restapi.smsbat.com/* | X-Authorization-Key · Authorization: Bearer · Autenticación básica |
El token de organización para X-Authorization-Key se emite en el panel bajo Perfil.
Los JWT de empresa y operador provienen de /api/company/get-token y /api/operator/get-token.
Discrepancia
El documento chatapi OpenAPI declara un esquema de seguridad único (Bearer) y lo aplica
globalmente. X-Authorization-Key no está declarado allí en absoluto, aunque el Meta interno
Comentarios La especificación API lo nombra como /api/meta/*. Lo más probable es que sea manejado por
middleware que no se refleja en Swagger. Confirme empíricamente antes de realizar el envío.
2.1 Token de empresa
POST https://chatapi.smsbat.com/api/company/get-token
Content-Type: application/json
{ "login": "company_login", "password": "company_password" }
200 OK devuelve una cadena de token simple.
2.2 Organizaciones
GET https://chatapi.smsbat.com/api/company/organization
Authorization: Bearer <company_token>
[ { "id": 24, "name": "My Instagram Store" } ]
2.3 Operadores en una organización
GET https://chatapi.smsbat.com/api/operator?organizationId=24
Authorization: Bearer <company_token>
[
{
"id": 21,
"name": "Jane Doe",
"status": 0,
"organization": { "id": 24, "name": "My Instagram Store" }
}
]
Estados del operador: 0 Activo, 1 Inactivo, 2 Eliminado.
2.4 Agregar/sincronizar operadores
POST https://chatapi.smsbat.com/api/operator/synchronize
Authorization: Bearer <company_token>
Content-Type: application/json
[ { "organizationId": 24, "name": "John Operator" } ]
200 OK → [ { "id": 21, "status": 0, "name": "John Operator" } ]
2.5 Operador JWT
POST https://chatapi.smsbat.com/api/operator/get-token
Authorization: Bearer <company_token>
Content-Type: application/json
{ "id": 21, "expiresAt": "2026-12-31T23:59:59.000Z" }
200 OK devuelve el JWT como una cadena.
2.6 Validar un token de operador
POST https://chatapi.smsbat.com/api/operator/validate-token
Authorization: Bearer <company_token>
Content-Type: application/json
"eyJhbGciOi..."
{
"isValid": true,
"operatorId": 21,
"clientId": 0,
"expiresAt": "2026-12-31T23:59:59.000Z",
"error": null
}
Cuando no es válido: { "isValid": false, "error": "Invalid token" }.
2.7 Incrustar el panel de chat del operador
<script type="module" id="operator-chat-panel-script"
src="https://widget.smsbat.com/operator-chat-panel/widget-script.js"
token="YOUR_OPERATOR_JWT_TOKEN"></script>
3. Enlaces profundos al panel de chat
Un sistema externo (CRM, ERP, sitio web) puede abrir una conversación específica en
https://chat.smsbat.com/. El operador está autorizado por un JWT pasado como parámetro de consulta.
https://chat.smsbat.com/?chat_raw_id=<chat_id>&token=<jwt>
https://chat.smsbat.com/?phone=<phone>&token=<jwt>
https://chat.smsbat.com/?from=<bm_id>&phone=<phone>&token=<jwt>
https://chat.smsbat.com/?source=7&from=<bm_id>&phone=<phone>&token=<jwt>
| Parámetro | Descripción |
|---|---|
chat_raw_id | ID de chat |
phone | Número de teléfono en formato internacional |
from | Identificador de cuenta de marca/empresa (bm_id) |
source | Fuente de chat: 7 para Instagram, consulte §8.1 |
token | Operador JWT válido y vigente con acceso a chats |
Un JWT no válido lleva al visitante a la pantalla de inicio de sesión del panel del operador.
4. Conversaciones directas de Instagram
4.1 Listar chats
GET https://chatapi.smsbat.com/api/chat/chats?source=7&page=1&per_page=20
Authorization: Bearer <token>
Note
La paginación aquí es per_page (snake_case). Bajo /api/meta/* y las encuestas
El punto final es perPage (camelCase). Esto no es un error tipográfico: la API usa ambos.
Parámetros de consulta, todos opcionales:
| Parámetro | Tipo | Descripción |
|---|---|---|
source | ChatSource | 7 restringe resultados a Instagram |
entityId | int | ID de cuenta comercial. Sólo se aplica junto con source |
instagram_user_id | int | ID de usuario de Instagram en ChatHub |
facebook_user_id | int | ID de usuario de Facebook en ChatHub |
page / per_page | int | Paginación, valores predeterminados 1 / 20 |
status | ChatStatus[] | Estado del chat, repetible |
search | string | Búsqueda de texto libre (nombre, teléfono,…) |
organizationId | int | ID de organización |
operatorId | int[] | Filtrar por operadores asignados |
date | string[] | Dos límites: ?date=…&date=… |
isChain | bool | Devolver chats como cadenas, llevando mensajes de chats anteriores |
isUnread, starMark, isOperator, isAIAgent | bool | Filtros adicionales |
phone, email, contactId, clientId, tagIds, rate, sortedBy | — | Otros filtros |
200 OK devuelve GetChatsResponse:
{
"total": 1,
"newMessagesCount": 2,
"items": [
{
"id": 1867,
"theme": null,
"messSource": 7,
"chatStatus": 1,
"countUnread": 2,
"metaUserId": "1585775752382460",
"instaAccount": { "id": 12, "name": "my_instagram_shop", "photo": "https://..." },
"instagramUser": { "id": 123, "name": "marianna_cat", "photo": "https://..." },
"operator": { "id": 21, "name": "Jane", "photo": "https://..." },
"client": { "id": 55, "name": "Marianna", "photo": null },
"textLastMess": "Hello! Is this product available?",
"timeLastMess": "2026-08-13T10:15:00Z",
"authorLastMessage": 1,
"messageStatus": 6,
"isMedia": false,
"phone": null,
"organizationId": 1,
"createdAt": "2026-08-13T10:14:00Z",
"isStarred": false,
"isBlocked": false,
"tags": []
}
]
}
Los campos que importan para una aplicación de Instagram:
| Campo | Significado |
|---|---|
instaAccount | La cuenta comercial de Instagram (la tienda). id es el valor del filtro entityId; name es el nombre de la cuenta de Meta |
instagramUser | El cliente**. name es el identificador de Instagram, id es el valor del filtro instagram_user_id |
metaUserId | ID de ámbito del cliente en el lado de Meta (cadena) |
messSource | 7 para Instagram |
phone | Generalmente null para Instagram: no lo use como clave |
ChatDTO también lleva olxUser, promUser, waba, rozetkaUser, facebookAccount,
facebookUser, viberAccount, tgBot, tgUser, viberBot, viberBotUser, widget,
media, isConnectedAI, isPromo, rate, rateComment, closedBy, draft, lang,
starMark, contactId, contactName, block, isInStopList, stopList,
isSmsFallbackEnabled y taggedMessages.
4.2 Mensajes de chat
GET https://chatapi.smsbat.com/api/chat/chats/1867/messages?isChain=false
Authorization: Bearer <token>
200 OK devuelve una matriz de ChatMessageDTO:
[
{
"id": 9928,
"chatId": 1867,
"message": "Hi! Do you have size M in stock?",
"messageTranslation": null,
"phone": null,
"author": 1,
"source": 7,
"media": null,
"replyTo": null,
"status": 6,
"date": "2026-08-13T10:14:00Z",
"operator": null,
"client": { "id": 123, "name": "marianna_cat", "photo": "https://..." },
"messageType": 0,
"isInternal": false,
"isBroadcast": false,
"starMark": false,
"referralGuid": null,
"postId": null,
"isConnectedAI": false,
"organizationId": 1,
"countUnreadMessages": 0
}
]
postId se completa cuando el mensaje se relaciona con una publicación o historia de Instagram: páselo
directamente de regreso como id / postId a la Meta API. media es un ChatMediaDTO:
{ name, format, type, uri, raw, length, isUploaded }.
4.3 Enviar un mensaje (JSON)
POST https://chatapi.smsbat.com/api/chat/1867/message
Authorization: Bearer <token>
Content-Type: application/json
Cuerpo - SendChatMessageDTO:
{
"textMessage": "Hello! Yes, size M is available.",
"author": 0,
"isInternal": false,
"replyToMessageId": 9928,
"appGuid": "550e8400-e29b-41d4-a716-446655440000",
"media": {
"name": "item.jpg",
"format": "image/jpeg",
"dataBase64": "/9j/4AAQSkZJRg...",
"type": 1
}
}
| Campo | Tipo | Descripción |
|---|---|---|
textMessage | string? | Texto del mensaje. Puede estar vacío cuando media está presente |
author | AuthorMessage? | 0 operador, 1 cliente |
isInternal | bool? | true marca una nota interna que no se entrega al cliente |
replyToMessageId | int? | ID del mensaje al que se responde |
appGuid | uuid? | GUID de referencia |
media | MediaDTO? | { name, format, dataBase64, thumbnail, duration, type } |
200 OK → { "id": 9930, "messageStatus": 0 }
También se puede pasar un GUID de referencia en la ruta:
POST /api/chat/{chatId}/{referralGuid}/message (igualmente …/message/v1, …/message/v2).
4.4 Enviar un archivo o vídeo (multiparte, v2)
POST https://chatapi.smsbat.com/api/chat/1867/message/v2
Authorization: Bearer <token>
Content-Type: multipart/form-data
Los nombres de los campos del formulario son PascalCase con notación de puntos
textMessage y media.file se ignoran silenciosamente. Utilice los nombres exactos a continuación.
| Campo de formulario | Tipo | Descripción |
|---|---|---|
TextMessage | string | Texto del mensaje |
Author | int | 0 operador, 1 cliente |
IsInternal | bool | Nota interna |
ReplyToMessageId | int | Mensaje respondido a |
AppGuid | uuid | GUID de referencia |
Media.File | binary | El archivo en sí |
Media.Name | string | Nombre del archivo |
Media.Format | string | Tipo MIME (video/mp4, image/png, application/pdf) |
Media.Type | MediaType | Véase §8.5 |
Media.DataBase64 | string | Alternativa a Media.File |
Media.Thumbnail | string | Cuadro de vista previa de vídeo Base64 |
Media.Duration | double | Duración del vídeo en segundos |
curl -X POST "https://chatapi.smsbat.com/api/chat/1867/message/v2" \
-H "Authorization: Bearer <token>" \
-F "TextMessage=Here is the price list" \
-F "Author=0" \
-F "Media.Type=2" \
-F "Media.File=@./price.pdf"
200 OK → { "id": 9931, "messageStatus": 0 }
4.5 Cambiar el estado del chat
PUT https://chatapi.smsbat.com/api/chat/status
Authorization: Bearer <token>
Content-Type: application/json
{ "id": 1867, "status": 4 }
200 OK hace eco del objeto actualizado.
4.6 Actualizar estados de mensajes
PUT https://chatapi.smsbat.com/api/chat/messages/status
Authorization: Bearer <token>
Content-Type: application/json
{ "status": 3, "messageIds": [9928, 9929] }
4.7 Eliminar un chat
DELETE https://chatapi.smsbat.com/api/chat/chats/1867
Authorization: Bearer <token>
5. Publicaciones, carretes e historias
Ruta base: https://chatapi.smsbat.com/api/meta
Autenticación: X-Authorization-Key: <organization token>
5.1 Listar publicaciones, carretes e historias
GET https://chatapi.smsbat.com/api/meta/posts?platform=instagram&mediaType=story&page=1&perPage=20
X-Authorization-Key: <token>
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
page | int | no | Página, predeterminada 1 |
perPage | int | no | Elementos por página, predeterminado 20 |
id | int | no | Filtrar por ID de publicación interna |
platform | string | no | instagram o facebook |
mediaType | string | no | post, reel o story. Todos los tipos cuando se omite |
# Every post
curl -H "X-Authorization-Key: <token>" \
"https://chatapi.smsbat.com/api/meta/posts?page=1&perPage=10"
# Instagram only
curl -H "X-Authorization-Key: <token>" \
"https://chatapi.smsbat.com/api/meta/posts?platform=instagram"
# A single post by ID
curl -H "X-Authorization-Key: <token>" \
"https://chatapi.smsbat.com/api/meta/posts?id=42"
# Instagram Stories only
curl -H "X-Authorization-Key: <token>" \
"https://chatapi.smsbat.com/api/meta/posts?platform=instagram&mediaType=story"
200 OK:
{
"total": 42,
"items": [
{
"id": 42,
"metaId": "18113450675314072",
"text": "Check out our new collection!",
"imageUrl": "https://dashboard.smsbat.com/api/meta/post/media/7d124c36-1711-4aa8-b21d-f6dbf8f347ef",
"platform": "instagram",
"mediaType": "story",
"createdAt": "2026-07-22T09:35:30Z",
"story": {
"id": 42,
"metaId": "18113450675314072",
"url": "https://dashboard.smsbat.com/api/meta/post/media/7d124c36-1711-4aa8-b21d-f6dbf8f347ef"
}
}
]
}
Discrepancia - nombre del campo del contador
El esquema Swagger MetaCommentPostListItemDtoPaginationDTO define total. el
Documentos de especificaciones internas totalCount. Swagger se genera a partir del código, por lo que
total es la verdad más probable. Analice total ?? totalCount hasta que esto se resuelva.
| Campo | Descripción |
|---|---|
id | ID de publicación interna |
metaId | Publicación externa/Reel/ID de historia en Meta |
text | Título de la publicación |
imageUrl | URL de medios proxy codificada por MetaPost.Guid o null no secuencial |
platform | facebook o instagram |
mediaType | post, reel o story |
createdAt | Fecha de creación (fecha de la plataforma o fecha de la base de datos) |
story | Presente solo por mediaType: "story" |
story.id | ID de historia interna; igual a post.id |
story.metaId | ID de historia externa en Meta |
story.url | URL proxy estable de los medios Story almacenados; null si no se pudieron guardar los medios |
Los medios postales se sirven por dos rutas: GET /api/meta/post/media/{id:int} para atrás
compatibilidad y GET /api/meta/post/media/{guid:guid}. Nuevas respuestas API y devoluciones de llamada
genere siempre el formulario GUID.
5.2 Listar comentarios
GET https://chatapi.smsbat.com/api/meta/comments?platform=instagram&postId=42&page=1&perPage=20
X-Authorization-Key: <token>
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
page | int | no | Página, predeterminada 1 |
perPage | int | no | Elementos por página, predeterminado 20 |
postId | int | no | Filtrar por ID de publicación |
parentCommentId | int | no | Comentarios secundarios (respuestas) de un comentario determinado |
platform | string | no | facebook o instagram |
200 OK:
{
"total": 100,
"items": [
{
"id": 5,
"metaId": "179000000000005",
"text": "What is the price?",
"createdAt": "2026-04-15T10:30:00Z",
"platform": "instagram",
"replyStatus": null,
"author": {
"type": "meta_user",
"name": "John Doe",
"metaUserId": "1585775752382460"
},
"post": {
"id": 1,
"metaId": "18113450675314072",
"text": null,
"imageUrl": "https://dashboard.smsbat.com/api/meta/post/media/7d124c36-…",
"createdAt": "2026-07-22T09:35:30Z",
"mediaType": "story",
"story": {
"id": 1,
"metaId": "18113450675314072",
"url": "https://dashboard.smsbat.com/api/meta/post/media/7d124c36-…"
}
},
"mediaUrl": "https://chatapi.smsbat.com/api/meta/comment/media/5",
"replyTo": {
"id": 3,
"metaId": "179000000000003",
"text": "Parent comment..."
}
}
]
}
| Campo | Descripción |
|---|---|
id | ID de comentario interno |
metaId | ID externo en Meta. null por una respuesta nuestra pendiente hasta que sea enviada |
text | Texto del comentario |
createdAt | Fecha de creación |
platform | facebook o instagram |
replyStatus | null para un comentario de usuario entrante; "pending" / "sent" / "failure" por nuestra respuesta |
author.type | "meta_user" usuario externo, "owner" propietario de la página |
author.name | Nombre del autor |
author.metaUserId | ID de usuario con ámbito en Meta; null para "owner" |
post | La publicación, carrete o historia a la que pertenece el comentario |
post.mediaType | post, reel o story |
post.story | Referencia de la historia { id, metaId, url }, solo historias |
mediaUrl | Medios adjuntos al comentario, o null |
replyTo | Comentario de los padres { id, metaId, text }; null al máximo nivel |
Discrepancia - tipo de `author.type`
La especificación interna documenta las cadenas "meta_user" / "owner". Tipos de arrogancia
MetaCommentAuthorType como entero con enumeración [0, 1]. Un JsonStringEnumConverter
explicaría la brecha, pero esto no se ha confirmado con una respuesta real. Escribe un
analizador que acepta ambos.
5.3 Responder a un comentario
Pone en cola una respuesta para su entrega.
curl -X POST \
-H "X-Authorization-Key: <token>" \
-H "Content-Type: application/json" \
-d '{"text": "Thanks for the feedback!"}' \
"https://chatapi.smsbat.com/api/meta/comments/5/reply"
Cuerpo de la solicitud: { "text": "Reply text" }
202 Accepted devuelve el objeto comentario (la misma forma que GET /api/meta/comments) con
replyStatus: "pending" y metaId: null. El resultado de la entrega llega más tarde como
source: 13 devolución de llamada (§6.4).
Discrepancia - código de respuesta
Swagger declara 200 sin cuerpo; la especificación interna declara 202 Accepted
con el comentario como cuerpo. Lo más probable es que al controlador le falte un ProducesResponseType
atributo, dejando Swagger en su valor predeterminado. Acepta cualquier 2xx y no dependas de un cuerpo.
6. Webhooks
SMSBAT envía POST solicitudes con application/json a su URL y espera HTTP 200 de respuesta.
Los campos nulos se omiten por completo
Un campo cuyo valor es null no se serializa en absoluto en el cuerpo de la devolución de llamada. por un
mensaje que no proviene de Facebook o Instagram simplemente no hay una clave MetaUserId.
Trate “ausente” y null como la misma cosa.
6.1 Registrar una URL de devolución de llamada
curl -X POST 'https://restapi.smsbat.com/organizations/callback_urls' \
-H 'X-Authorization-Key: <token>' \
-H 'Content-Type: application/json' \
-d '{
"url": "https://your-server.com/webhook",
"source": 12,
"headerName": "X-Webhook-Secret",
"headerValue": "your-secret",
"channelType": 7,
"channelEntityId": 12
}'
| Campo | Tipo | Descripción |
|---|---|---|
url | string | Su punto final |
source | SendingSourceCallback | Tipo de evento, consulte §8.2 |
headerName / headerValue | string | Encabezado de autenticación arbitrario que adjuntamos a la solicitud (opcional) |
channelType | ChatSource | Canal. 7 para Instagram. Opcional |
channelEntityId | int | Una cuenta comercial específica. Requiere channelType |
Sin channelType la URL recibe eventos de todos los canales.
Tip
La cobertura completa de comentarios necesita dos registros: source: 12 para nuevos comentarios y
source: 13 para estados de respuesta. Para respuestas directas y de historias, agregue source: 3
(y 11 si quieres todos los mensajes de chat).
Operaciones restantes:
GET https://restapi.smsbat.com/organizations/callback_urls?source=12
GET https://restapi.smsbat.com/organizations/callback_urls/{id}
PUT https://restapi.smsbat.com/organizations/callback_urls/{id}
DELETE https://restapi.smsbat.com/organizations/callback_urls/{id}
GET devuelve:
[
{
"id": 101,
"url": "https://your-server.com/webhook",
"source": 12,
"headerName": "X-Webhook-Secret",
"headerValue": "your-secret",
"createdAt": "2026-08-13T09:00:00Z",
"channelType": 7,
"channelEntityId": 12
}
]
6.2 Nuevo mensaje y respuesta a la historia de Instagram (source: 3, 11)
La respuesta de un usuario a una Historia de Instagram llega como un mensaje normal en estas devoluciones de llamada.
con un bloque Story adicional de nivel superior:
{
"ChatId": 123,
"MessageId": 456,
"MessageText": "😍",
"Username": "Jane Smith",
"UserId": 789,
"MetaUserId": "1585775752382460",
"ShopId": 12,
"ShopName": "instagram shop name",
"Author": 0,
"type_messenger": 7,
"Story": {
"Id": 42,
"MetaId": "18113450675314072",
"Url": "https://dashboard.smsbat.com/api/meta/post/media/7d124c36-1711-4aa8-b21d-f6dbf8f347ef"
}
}
| Campo | Descripción |
|---|---|
ChatId / MessageId | Identificadores de chat y mensajes |
Author | 0 usuario, 1 operador |
Username | Nombre para mostrar o identificador de Instagram/Facebook |
UserId | ID de usuario numérico interno en SMSBAT |
MetaUserId | ID de ámbito del interlocutor de conversación en Meta. En un mensaje de operador saliente, esto aún identifica al metausuario del chat, no al operador |
ShopId | ID interno de la cuenta comercial de Instagram/Facebook |
ShopName | Nombre de la cuenta comercial recibido de Meta en el momento de la conexión |
MessageText | Texto del mensaje |
MessageMedia | URL de medios cuando el mensaje es multimedia |
type_messenger | Fuente, 7 para Instagram |
operator_name | Nombre del operador cuando Author = 1 |
Story | Presentar solo en una respuesta entrante de Historia |
Story.Id | ID de historia interna (MetaPost): utilizable directamente como id / postId en Meta API |
Story.MetaId | ID de historia externa en Meta |
Story.Url | URL de proxy estable de los medios de Story almacenados. Ausente cuando no se pudieron guardar los medios: el bloque Story y el mensaje aún se entregan |
`Author` está invertido en relación con la API de chat
En ChatMessageDTO.author, 0 significa operador y 1 significa cliente. En esta devolución de llamada es
al revés: 0 es el usuario, 1 es el operador. No compartas el mapeo.
6.3 Nuevo comentario (source: 12)
Se activa cuando un usuario Meta comenta en una publicación de Facebook o una publicación/Reel de Instagram.
Note
Instagram Las respuestas a las historias no se entregan a través del source: 12. Llegan con normalidad
mensajes entrantes en source: 3 y/o 11 con un bloque Story; consulte §6.2.
{
"type": "new_comment",
"platform": "instagram",
"comment": {
"id": 10,
"metaId": "179000000000010",
"parentCommentId": 5,
"parentMetaId": "179000000000005",
"parentCommentText": "The user's previous comment",
"text": "Great product!",
"createdAt": "2026-04-16T12:00:00Z",
"author": {
"type": "meta_user",
"name": "Jane Smith",
"metaUserId": "1585775752382460"
}
},
"post": {
"id": 1,
"metaId": "123456789012345",
"text": "Post description...",
"imageUrl": "https://dashboard.smsbat.com/api/meta/post/media/7d124c36-…",
"createdAt": "2026-04-10T12:00:00Z",
"mediaType": "post"
}
}
6.4 Estado de respuesta al comentario (source: 13)
Se activa después de que intentamos dar una respuesta, ya sea que tenga éxito o falle.
{
"type": "comment_status",
"platform": "instagram",
"comment": {
"id": 15,
"metaId": "179000000000015",
"parentCommentId": 10,
"parentMetaId": "179000000000010",
"parentCommentText": "Great product!",
"text": "Thanks for the feedback!",
"createdAt": "2026-04-16T12:05:00Z",
"updatedAt": "2026-04-16T12:05:03Z",
"replyStatus": "sent",
"author": {
"type": "owner",
"name": "Support Agent"
}
},
"post": {
"id": 1,
"metaId": "179999999999999",
"text": "Reel description...",
"imageUrl": "https://dashboard.smsbat.com/api/meta/post/media/7d124c36-…",
"createdAt": "2026-07-22T09:35:30Z",
"mediaType": "reel"
}
}
6.5 Campos de devolución de llamada de comentarios compartidos
Ambas devoluciones de llamada de comentarios comparten una forma de cuerpo y solo difieren en type.
| Campo | Descripción |
|---|---|
type | "new_comment" o "comment_status" |
platform | "facebook" o "instagram" |
comment.id | ID de comentario interno |
comment.metaId | ID externa en Meta; null para una respuesta pendiente antes de enviarla |
comment.parentCommentId | ID de comentario de los padres. Ausente para un comentario de nivel superior |
comment.parentMetaId | ID de comentario externo de los padres. Ausente al máximo nivel |
comment.parentCommentText | Texto de comentario de los padres. Ausente al máximo nivel |
comment.text | Texto del comentario |
comment.createdAt | Fecha de creación |
comment.updatedAt | Última actualización. Ausente si el comentario nunca fue editado |
comment.replyStatus | "pending" / "sent" / "failure". Ausente para un comentario de usuario entrante |
comment.author.type | "meta_user" o "owner" |
comment.author.name | Nombre del autor |
comment.author.metaUserId | ID de autor con alcance en Meta. Ausente por "owner" |
comment.mediaUrl | Medios de comentarios. Ausente cuando no hay ninguno |
post.id | ID de publicación interna |
post.metaId | Publicación externa/Reel/ID de historia en Meta |
post.text | Publicar texto |
post.imageUrl | Publicar URL de la imagen, o null |
post.createdAt | Fecha de creación de la publicación |
post.mediaType | En devoluciones de llamada de comentarios, solo post o reel |
6.6 Nuevo chat (source: 7)
{ "ChatId": 12345, "Phone": "+380501234567", "chat.Source": 7 }
6.7 Cambios de estado de mensajes y chats (source: 6 / 5)
{ "name": "changed_message_status", "id": 9928, "status": 6 }
{ "name": "changed_chat_status", "id": 1867, "status": 4 }
6.8 Mensaje editado o eliminado (source: 9)
{ "messageId": 9930, "text": "Updated message text" }
{ "messageId": 9931, "delete": true }
6.9 Indicador de escritura (source: 8)
{ "chat_id": 1867, "event": "start_typing", "operator_name": "Iryna" }
{ "chat_id": 1867, "event": "end_typing" }
7. Encuesta de eventos
Para entornos que no pueden aceptar HTTP entrante.
7.1 Recuperar eventos
GET https://chatapi.smsbat.com/api/chat/callback-events?page=1&perPage=20
Authorization: Bearer <token>
| Parámetro | Descripción |
|---|---|
organizationId | Opcional. Tomado del token cuando se omite |
page / perPage | Paginación, valores predeterminados 1 / 20 |
{
"page": 1,
"perPage": 20,
"total": 947,
"items": [
{
"ChatId": 1867,
"MessageId": 9928,
"MessageText": "Hello there!",
"MessageMedia": null,
"Phone": null,
"Username": "marianna_cat",
"UserId": 123,
"ShopId": 12,
"ShopName": "instagram shop name",
"Author": 1,
"type_messenger": 7,
"message_date": "2026-08-13T12:27:39.724Z",
"timestamp": "2026-08-13T12:27:39.736Z",
"event_guid": "ff60129e-c6e4-4876-9d90-badb430c0606",
"organization_id": 1,
"callback_type": "3"
}
]
}
Cada evento lleva event_guid, timestamp, organization_id y callback_type - un
cadena que coincide con los valores source en §8.2. Los campos restantes coinciden con los correspondientes.
webhook en §6.
7.2 Confirmar eventos procesados
POST https://chatapi.smsbat.com/api/chat/callback-events/processed
Authorization: Bearer <token>
Content-Type: application/json
[ "ff60129e-c6e4-4876-9d90-badb430c0606" ]
200 OK → { "deleted": 1 }
Los eventos ya eliminados simplemente no cuentan para deleted. Realizar pedidos y reintentar son suyos.
responsabilidad del lado.
7.3 Bucle recomendado
- Encuesta
GET /api/chat/callback-eventssegún un cronograma. - Procesa los eventos en tu servicio.
- Envíe la lista
event_guidprocesada a/callback-events/processed. - Repita.
8. Referencia de enumeración
8.1 ChatSource — canal (0–9)
| Código | Canal |
|---|---|
| 0 | Viber |
| 1 | ViberBot |
| 2 | TelegramaBot |
| 3 | |
| 4 | Reproductor |
| 5 | Rozetka |
| 6 | |
| 7 | |
| 8 | Fiesta de graduación |
| 9 | Olx |
8.2 SendingSourceCallback — tipo de evento de devolución de llamada (0–13)
| Código | Evento |
|---|---|
| 3 | Chat — nuevo mensaje de chat, incluidas las respuestas de la historia |
| 5 | El estado del chat cambió |
| 6 | Estado del mensaje cambiado |
| 7 | Nuevo chat creado |
| 8 | Indicador de escritura |
| 9 | Mensaje actualizado o eliminado |
| 11 | AnyChatMessage — cualquier mensaje de chat |
| 12 | MetaNewComment — nuevo comentario de Instagram/Facebook |
| 13 | MetaCommentStatus — estado de entrega de nuestra respuesta al comentario |
La enumeración abarca 0–13; los valores restantes no son necesarios para las integraciones de Instagram.
8.3 ChatStatus (0–4)
0 Nuevo, 1 Abierto, 2 En espera, 3 En pausa, 4 Cerrado
8,4 MessageStatus (0–11)
| Código | Nombre |
|---|---|
| 0 | NUEVO |
| 1 | ÉXITO |
| 2 | RECHAZADO |
| 3 | LEER |
| 4 | DESCONOCIDO |
| 5 | PROCESAMIENTO |
| 6 | ENTREGADO |
| 7 | BLOQUEADO_POR_USUARIO |
| 8 | USUARIO_NO_ENCONTRADO |
La enumeración abarca 0–11. Los valores 9, 10 y 11 existen en la API pero aún no están documentados:
trátelos como UNKNOWN.
8,5 MediaType (1–10)
1 Foto, 2 Archivo, 3 Audio, 4 Vídeo, 5 Adhesivo, 6 Adhesivo animado,
7 StickerVideo, 8 Animación, 9 Voz, 10 VideoNote
8.6 AuthorMessage — autor en Chat API (0–4)
0 Operador, 1 Cliente, 2 Bot, 3 ViberAccount
La enumeración abarca 0–4; El valor 4 no está documentado. Las devoluciones de llamada de “mensaje nuevo” utilizan el
mapeo opuesto — ver §6.2.
8,7 ChatMessageType (0–2)
0 Texto, 1 Foto, 2 Archivo
8.8 Comentario replyStatus
null comentario de usuario entrante, "pending" nuestra respuesta está en cola, "sent" entregada,
"failure" la entrega falló.
Preguntas abiertas
Tres puntos en los que la especificación interna y el Swagger generado por el código no están de acuerdo. uno la solicitud con un token real los liquida todos; Hasta entonces, escriba al cliente a la defensiva.
| # | Pregunta | Especificación | Arrogancia | Cómo comprobarlo |
|---|---|---|---|---|
| 1 | Encabezado de autenticación para /api/meta/* | X-Authorization-Key | sólo Bearer declarado | curl -i -H "X-Authorization-Key: <token>" ".../api/meta/posts?perPage=1" — espere 200, no 401 |
| 2 | Campo de contador en Meta respuestas | totalCount | total | Misma solicitud: lea la clave JSON raíz |
| 3 | author.type tipo y reply código de estado | "meta_user" / "owner", 202 con cuerpo | int [0,1], 200 sin cuerpo | curl -i .../api/meta/comments?perPage=1 más una respuesta de prueba |
Orientación provisional:
- contador - lea
total ?? totalCount; author.type: acepta tanto una cadena como un número entero (0↔meta_user,1↔owner, asignación por confirmar);reply: trate cualquier2xxcomo un éxito, no requiera ningún cuerpo, tome el estado final de la devolución de llamadasource: 13.
Notas de implementación
- La autenticación difiere según el grupo de puntos finales:
/api/meta/*usaX-Authorization-Key, chats y los operadores usanBearer,restapiacepta cualquiera de los dos. - La paginación se escribe de dos maneras:
per_pageen/api/chat/chats,perPageen/api/meta/*y/api/chat/callback-events. multipart/form-datalos campos son PascalCase con notación de puntos (Media.File,Media.Type).- Los campos nulos se omiten en las devoluciones de llamada: una clave ausente significa
null. phonesuele sernullen Instagram. Identificar al cliente porinstagramUser.id/metaUserIdy comprar porinstaAccount.id(el valor del filtroentityId).Story.Idde una devolución de llamada se puede pasar directamente comoid/postIda la Meta API.- Verifique el JWT del operador
expiresAtantes de usarlo en un enlace profundo o en el widget.