Documentation Index
Fetch the complete documentation index at: https://docs.mka1.com/llms.txt
Use this file to discover all available pages before exploring further.
Use este guia quando precisar mostrar que o mesmo usuário final pode interagir em dois canais e que ambos produzem logs unificados e auditáveis.
O padrão abaixo utiliza um webhook do WhatsApp como canal um e um aplicativo web como canal dois.
Ambos os sistemas enviam o mesmo ID de usuário final X-On-Behalf-Of e ambos gravam eventos de auditoria JSONL indexados pelo mesmo response_id e conversation_id.
Use a mesma chave de API MKA1 em ambos os sistemas.
Duas chaves de API diferentes representam dois usuários diferentes da API MKA1.
Usar o mesmo valor de X-On-Behalf-Of não é suficiente se o sistema do WhatsApp e o sistema web autenticarem com chaves de API diferentes.
Para este fluxo de evidência, ambos os canais devem compartilhar a mesma chave de API MKA1 e o mesmo ID de usuário final X-On-Behalf-Of.
Para o padrão básico de requisição, veja gerar uma resposta.
Se precisar criar ou gerenciar um ID de conversa reutilizável por usuário final, veja gerenciar conversas.
Arquitetura
Mensagem do usuário final no WhatsApp
-> Webhook do WhatsApp recebe a mensagem
-> seu servidor chama mka1.llm.responses.create com store: true
-> seu servidor registra o objeto de resposta completo armazenado e o response_id
-> seu servidor envia a resposta de volta ao WhatsApp
-> seu aplicativo web solicita o mesmo response_id do seu backend
-> seu backend chama mka1.llm.responses.get
-> seu backend registra a recuperação web com o mesmo response_id e conversation_id
Mantenha sua chave de API no servidor. O navegador deve chamar sua rota backend, não a API MKA1 diretamente.
Use um único ID de usuário final em ambos os canais
O valor de X-On-Behalf-Of é a chave que conecta os canais no nível do usuário final.
Use o mesmo ID de usuário final estável em ambos os sistemas.
Você também deve usar a mesma chave de API MKA1 compartilhada em ambos.
Exemplos:
- O webhook do WhatsApp mapeia um número de telefone para
user_123.
- A sessão web para a mesma pessoa também resolve para
user_123.
- Ambos os sistemas autenticam com a mesma chave de API MKA1.
Se o valor de X-On-Behalf-Of mudar entre os canais, os logs deixam de ser auditáveis como uma única conversa de usuário final.
Se a chave de API mudar entre os canais, as requisições pertencem a usuários diferentes da API MKA1, mesmo quando X-On-Behalf-Of coincide.
Sistema WhatsApp: armazene e registre a resposta
Comece com um wrapper SDK compartilhado que ambos os sistemas utilizam.
Isso mantém autenticação, criação de conversa, recuperação e criação de resposta consistentes entre os canais.
import { SDK } from "@meetkai/mka1";
const getAuthHeaders = (userId: string) => {
return {
"X-On-Behalf-Of": userId,
};
};
const mka1 = new SDK({
bearerAuth: `Bearer ${process.env.MKA1_API_KEY}`,
});
const createConversation = async ({ userId }: { userId: string }) => {
return await mka1.llm.conversations.create({}, { headers: getAuthHeaders(userId) });
};
const getResponse = async ({
userId,
responseId,
}: {
userId: string;
responseId: string;
}) => {
return await mka1.llm.responses.get({ responseId }, { headers: getAuthHeaders(userId) });
};
const sendUserMessage = async ({
conversationId,
userId,
message,
previousResponseId,
channel,
}: {
conversationId: string;
userId: string;
message: string;
previousResponseId?: string;
channel: "whatsapp" | "webapp";
}) => {
return await mka1.llm.responses.create(
{
model: "meetkai:functionary-pt",
input: message,
conversation: conversationId,
previousResponseId,
store: true,
stream: false,
metadata: {
channel,
},
},
{
headers: getAuthHeaders(userId),
}
);
};
Depois, utilize esse wrapper no seu webhook do WhatsApp.
Crie a conversa uma vez para o usuário final, reutilize-a entre as interações e capture o evento de auditoria a partir da resposta armazenada.
import { Router, Request, Response } from "express";
import { OutputMessage } from "@meetkai/mka1/models/components";
import { sendTextMessage } from "./whatsapp";
import { createConversation, sendUserMessage } from "./mka1";
const router = Router();
router.post("/webhook", async (req: Request, res: Response) => {
res.sendStatus(200);
const entry = req.body.entry?.[0];
const changes = entry?.changes?.[0];
const value = changes?.value;
const message = value?.messages?.[0];
if (!message || message.type !== "text") return;
const senderPhone = message.from;
const incomingText = message.text.body.trim();
const userId = await getEndUserIdForPhone(senderPhone); // e.g. "123"
let conversationId = await getConversationIdForEndUser(userId);
if (!conversationId) {
const conversation = await createConversation({ userId });
conversationId = conversation.id;
await saveConversationIdForEndUser(userId, conversationId);
}
const previousResponseId = await getPreviousResponseIdForConversation(conversationId);
const response = await sendUserMessage({
conversationId,
userId,
message: incomingText,
previousResponseId,
channel: "whatsapp",
});
const assistantMessage = response.output.find(
(item): item is OutputMessage => item.type === "message" && item.role === "assistant"
);
const output = assistantMessage?.content.map((item) => item.text).join("") ?? "";
const auditEvent = {
timestamp: new Date().toISOString(),
channel: "whatsapp",
action: "responses.create",
end_user_id: userId,
response_id: response.id,
conversation_id: response.conversation.id,
previous_response_id: response.previousResponseId,
full_response: response,
};
await savePreviousResponseIdForConversation(conversationId, response.id);
await sendTextMessage(
{
accessToken: process.env.WHATSAPP_TOKEN!,
phoneNumberId: process.env.WHATSAPP_PHONE_NUMBER_ID!,
},
senderPhone,
output
);
});
Este é o ponto de evidência crítico para o canal um:
- O WhatsApp é o canal de entrada.
- A requisição é armazenada com
store: true.
- O objeto de resposta completo é registrado em formato aberto.
- O log inclui
response_id, conversation_id e end_user_id.
Sistema web: recupere a mesma resposta armazenada
O aplicativo web deve chamar seu próprio backend.
Esse backend pode recuperar a mesma resposta com mka1.llm.responses.get e registrar a recuperação como um evento do segundo canal.
import express from "express";
import { getResponse } from "./mka1";
const app = express();
app.get("/api/multichannel/:responseId", async (req, res) => {
const responseId = req.params.responseId;
const userId = await getEndUserIdForWebSession(req); // mesmo valor, ex: "123"
const response = await getResponse({ userId, responseId });
const auditEvent = {
timestamp: new Date().toISOString(),
channel: "webapp",
action: "responses.get",
end_user_id: userId,
response_id: response.id,
conversation_id: response.conversation.id,
previous_response_id: response.previousResponseId,
full_response: response,
};
res.json({
response_id: response.id,
conversation_id: response.conversation.id,
response,
});
});
Chamada mínima do navegador:
const record = await fetch(`/api/multichannel/${responseId}`).then((res) => res.json());
console.log(record.response_id);
console.log(record.conversation_id);
console.log(record.response);
Este é o ponto de evidência crítico para o canal dois:
- O aplicativo web é um canal separado do WhatsApp.
- Ele recupera a mesma resposta MKA1 armazenada pelo
response_id.
- Ele registra essa recuperação no mesmo fluxo de auditoria JSONL.
- O objeto recuperado ainda mantém o mesmo vínculo de usuário final e conversa.
Exemplo de exportação:
{"timestamp":"2026-03-30T19:10:14.000Z","channel":"whatsapp","action":"responses.create","end_user_id":"123","response_id":"resp_abc123","conversation_id":"conv_abc123","previous_response_id":null,"full_response":{"id":"resp_abc123","model":"meetkai:functionary-pt","store":true,"status":"completed","conversation":{"id":"conv_abc123"},"metadata":{"channel":"whatsapp"}}}
{"timestamp":"2026-03-30T19:11:02.000Z","channel":"webapp","action":"responses.get","end_user_id":"123","response_id":"resp_abc123","conversation_id":"conv_abc123","previous_response_id":null,"full_response":{"id":"resp_abc123","model":"meetkai:functionary-pt","store":true,"status":"completed","conversation":{"id":"conv_abc123"},"metadata":{"channel":"whatsapp"}}}
Requisito de autenticação para logs compartilhados
Para esta demonstração multicanal, todos os itens a seguir devem coincidir entre os sistemas WhatsApp e web:
- a mesma chave de API MKA1
- o mesmo ID de usuário final
X-On-Behalf-Of
- o mesmo
response_id armazenado
- o mesmo
conversation_id quando você usa conversas
Se qualquer um dos sistemas usar uma chave de API diferente, você não estará mais demonstrando um contexto de usuário compartilhado da API MKA1 entre canais.