Agenda
Referência das seis rotas da Agenda na API do ChatISP: consulte os tipos de compromisso, liste e consulte a agenda da equipe, marque visitas, retornos e reuniões a partir de outro sistema e registre a conclusão ou o cancelamento.
Visão geral
A Agenda do ChatISP guarda os compromissos da equipe: visita técnica, retorno de contato, instalação, reunião. Cada compromisso pode ter responsável, equipe, cliente e atendimento vinculado, e dispara sozinho os avisos ao responsável e os lembretes ao cliente pelo WhatsApp. Pela API, o seu sistema marca e acompanha esses compromissos com as mesmas regras da tela.
Casos típicos de integração:
- ERP e ordens de serviço: a OS de instalação agendada no ERP vira compromisso na agenda do técnico, com lembrete automático ao cliente na véspera.
- Portal do assinante: o cliente escolhe o horário da visita no portal e o compromisso nasce já com a confirmação enviada pelo WhatsApp.
- Aplicativo de campo: o técnico vê a agenda do dia e marca a visita como concluída, com o desfecho.
- Roteirização: um sistema externo lê a agenda da semana por equipe para planejar rotas.
Rotas
| Rota | Método | Permissão da chave | O que faz |
|---|---|---|---|
agenda/tipos | GET | Consultar agenda | Tipos de compromisso e a duração padrão de cada um. |
agenda/listar | GET | Consultar agenda | Compromissos de um período, com filtros. |
agenda/consultar | GET | Consultar agenda | Um compromisso. |
agenda/criar | POST | Gerenciar agenda | Marca um compromisso. |
agenda/concluir | POST | Gerenciar agenda | Marca como concluído, com desfecho. |
agenda/cancelar | POST | Gerenciar agenda | Cancela, com motivo. |
As permissões são marcadas na chave, em Integrações, card API do ChatISP. Gerenciar agenda não inclui a leitura: para marcar e depois consultar, marque as duas. Autenticação, formato das chamadas, paginação e erros comuns estão na Introdução.
A chave enxerga a agenda da casa inteira, de todas as equipes e responsáveis. As regras de quem vê o quê no painel valem para as pessoas, não para a API. Compromissos marcados pela API ficam com origem igual a api e, nas notas do atendimento vinculado, a ação aparece como feita por API: <nome da chave>.
O objeto compromisso
Formato usado por todas as rotas que devolvem compromissos. Datas em ISO 8601 com o fuso do servidor.
| Campo | Tipo | Descrição |
|---|---|---|
id | inteiro | Identificador do compromisso. |
titulo | texto | Título, até 160 caracteres. |
tipo | objeto ou null | {"id", "nome"} do tipo; null sem tipo. |
descricao | texto | Observações; vazio quando não há. |
inicio / fim | data | Começo e fim. Sempre em minutos cheios (os segundos são zerados). |
dia_inteiro | booleano | true no compromisso de dia inteiro: inicio às 00:00 e fim às 23:59 do mesmo dia. |
local | texto | Endereço ou ponto de encontro. |
link | texto | Link da reunião (por exemplo, a sala do Google Meet criada para o compromisso). |
estado | texto | agendado, concluido ou cancelado. |
origem | texto | manual (marcado na Agenda), chat (marcado a partir de um atendimento), copiloto, ia ou api. |
responsavel_id / responsavel | inteiro ou null / texto | Pessoa responsável. |
departamento_id | inteiro ou null | Equipe do compromisso. |
conversa_id | inteiro ou null | Atendimento vinculado. |
cliente | objeto | {"telefone", "nome"}. Telefone com DDI, só dígitos; vazio quando o compromisso não tem cliente. |
desfecho | texto | O que foi registrado ao concluir ou cancelar. |
criado_em / atualizado_em | data | Criação e última alteração do registro. |
{
"id": 342,
"titulo": "Visita técnica: troca de roteador",
"tipo": {"id": 3, "nome": "Visita técnica"},
"descricao": "Levar roteador dual band. Portão azul, interfone 2.",
"inicio": "2026-10-02T09:00:00-03:00",
"fim": "2026-10-02T10:00:00-03:00",
"dia_inteiro": false,
"local": "Rua das Palmeiras, 120, Centro",
"link": "",
"estado": "agendado",
"origem": "api",
"responsavel_id": 7,
"responsavel": "Carlos Lima",
"departamento_id": 3,
"conversa_id": 5310,
"cliente": {"telefone": "5544999990000", "nome": "Maria Souza"},
"desfecho": "",
"criado_em": "2026-10-01T14:20:03-03:00",
"atualizado_em": "2026-10-01T14:20:03-03:00"
}Estados
estado | Significado |
|---|---|
agendado | Compromisso vigente. Só ele dispara avisos ao responsável e lembretes ao cliente. |
concluido | Realizado. Os alertas pendentes são descartados. |
cancelado | Não vai acontecer. Os alertas pendentes são descartados e o evento espelhado no Google Agenda é removido. |
Tipos de compromisso
/api_publica.php?r=agenda/tiposDevolve os tipos de compromisso cadastrados, na ordem da tela, inclusive os desativados. Sem parâmetros. O tipo define a duração padrão, as antecedências dos avisos ao responsável e dos lembretes ao cliente, e se o evento no Google Agenda nasce com sala do Meet.
Campo de tipos[] | Descrição |
|---|---|
id | Identificador, usado em tipo_id. |
nome | Nome do tipo. |
ativo | false quando desativado. |
duracao_min | Duração padrão em minutos, usada para calcular o fim quando a marcação não informa fim nem duracao_min. |
curl -s -G "https://atendimento.seuprovedor.com.br/api_publica.php" \ -H "Authorization: Bearer $CHATISP_CHAVE" \ --data-urlencode "r=agenda/tipos"
<?php
$url = 'https://atendimento.seuprovedor.com.br/api_publica.php?' . http_build_query([
'r' => 'agenda/tipos',
]);
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('CHATISP_CHAVE')],
]);
$resposta = json_decode(curl_exec($ch), true);import os, requests
resposta = requests.get(
"https://atendimento.seuprovedor.com.br/api_publica.php",
params={"r": "agenda/tipos"},
headers={"Authorization": "Bearer " + os.environ["CHATISP_CHAVE"]},
timeout=30,
).json(){
"ok": true,
"tipos": [
{"id": 1, "nome": "Reunião", "ativo": true, "duracao_min": 60},
{"id": 2, "nome": "Retorno de contato", "ativo": true, "duracao_min": 15},
{"id": 3, "nome": "Visita técnica", "ativo": true, "duracao_min": 60},
{"id": 4, "nome": "Treinamento", "ativo": true, "duracao_min": 90},
{"id": 5, "nome": "Apresentação", "ativo": true, "duracao_min": 60}
]
}Os tipos e as antecedências de cada um são configurados pelo provedor na Agenda: veja Tipos de compromisso.
Listar compromissos
/api_publica.php?r=agenda/listarCompromissos que tocam o período pedido (começam antes do fim do período e terminam depois do começo dele), em ordem de início. Um compromisso das 23:00 às 01:00 aparece tanto no dia em que começa quanto no seguinte.
| Parâmetro | Tipo | Descrição |
|---|---|---|
de | data | Começo do período. Padrão: hoje, 00:00. |
ate | data | Fim do período. Padrão: 30 dias depois de de, às 23:59:59. Data sem hora vale até 23:59:59 do dia. O período máximo é de 366 dias. |
estado | texto | agendado, concluido ou cancelado. Sem ele, todos. |
responsavel_id | inteiro | Só os dessa pessoa. |
departamento_id | inteiro | Só os dessa equipe. |
tipo_id | inteiro | Só os desse tipo. |
conversa_id | inteiro | Só os vinculados a esse atendimento. |
telefone | texto | Só os desse cliente (procurado com e sem o nono dígito). |
pagina / limite | inteiro | Paginação numerada: limite de 1 a 100 (padrão 50). |
curl -s -G "https://atendimento.seuprovedor.com.br/api_publica.php" \ -H "Authorization: Bearer $CHATISP_CHAVE" \ --data-urlencode "r=agenda/listar" \ --data-urlencode "de=2026-10-02" \ --data-urlencode "ate=2026-10-02" \ --data-urlencode "responsavel_id=7" \ --data-urlencode "estado=agendado"
<?php
$url = 'https://atendimento.seuprovedor.com.br/api_publica.php?' . http_build_query([
'r' => 'agenda/listar',
'de' => '2026-10-02',
'ate' => '2026-10-02',
'responsavel_id' => 7,
'estado' => 'agendado',
]);
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('CHATISP_CHAVE')],
]);
$resposta = json_decode(curl_exec($ch), true);import os, requests
resposta = requests.get(
"https://atendimento.seuprovedor.com.br/api_publica.php",
params={"r": "agenda/listar", "de": "2026-10-02", "ate": "2026-10-02", "responsavel_id": 7, "estado": "agendado"},
headers={"Authorization": "Bearer " + os.environ["CHATISP_CHAVE"]},
timeout=30,
).json(){
"ok": true,
"periodo": {"de": "2026-10-02T00:00:00-03:00", "ate": "2026-10-02T23:59:59-03:00"},
"compromissos": [
{
"id": 342,
"titulo": "Visita técnica: troca de roteador",
"tipo": {"id": 3, "nome": "Visita técnica"},
"inicio": "2026-10-02T09:00:00-03:00",
"fim": "2026-10-02T10:00:00-03:00",
"estado": "agendado",
"local": "Rua das Palmeiras, 120, Centro",
"cliente": {"telefone": "5544999990000", "nome": "Maria Souza"},
"...": "demais campos do objeto compromisso"
}
],
"paginacao": {"pagina": 1, "limite": 50, "total": 1, "paginas": 1}
}O bloco periodo devolve o período efetivamente usado, o que ajuda a conferir os padrões quando de ou ate foram omitidos.
Consultar um compromisso
/api_publica.php?r=agenda/consultar| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
id | inteiro | sim | Id do compromisso. |
curl -s -G "https://atendimento.seuprovedor.com.br/api_publica.php" \ -H "Authorization: Bearer $CHATISP_CHAVE" \ --data-urlencode "r=agenda/consultar" \ --data-urlencode "id=342"
<?php
$url = 'https://atendimento.seuprovedor.com.br/api_publica.php?' . http_build_query([
'r' => 'agenda/consultar',
'id' => 342,
]);
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('CHATISP_CHAVE')],
]);
$resposta = json_decode(curl_exec($ch), true);import os, requests
resposta = requests.get(
"https://atendimento.seuprovedor.com.br/api_publica.php",
params={"r": "agenda/consultar", "id": 342},
headers={"Authorization": "Bearer " + os.environ["CHATISP_CHAVE"]},
timeout=30,
).json(){
"ok": true,
"compromisso": {"id": 342, "titulo": "Visita técnica: troca de roteador", "...": "objeto compromisso completo"}
}Marcar um compromisso
/api_publica.php?r=agenda/criarMarca um compromisso no estado agendado. Título e início são obrigatórios; o fim pode vir explícito, por duração ou pelo tipo.
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
titulo | texto | sim | De 1 a 160 caracteres. |
inicio | data | sim | Data e hora de início (ISO 8601 ou AAAA-MM-DD HH:MM:SS no fuso do servidor). |
fim | data | não | Data e hora de término. Precisa ser depois do início. |
duracao_min | inteiro | não | Duração em minutos, usada quando fim não vem. |
dia_inteiro | booleano | não | Compromisso do dia todo: ocupa o dia de inicio das 00:00 às 23:59, e fim e duracao_min são ignorados. |
tipo_id | inteiro | não | Tipo do compromisso (agenda/tipos). Tipo inexistente ou desativado dá tipo_invalido. |
descricao | texto | não | Observações, até 5.000 caracteres. |
local | texto | não | Endereço ou ponto de encontro, até 255 caracteres. |
link | texto | não | Link da reunião, começando com http:// ou https://, até 500 caracteres. |
responsavel_id | inteiro | não | Pessoa responsável (ativa). |
departamento_id | inteiro | não | Equipe do compromisso. |
conversa_id | inteiro | não | Atendimento vinculado. Completa telefone e nome do cliente quando não informados. |
telefone | texto | não | WhatsApp do cliente, para confirmação e lembretes. Mesma regra de telefone do resto da API. |
nome_cliente | texto | não | Nome do cliente, até 190 caracteres. Vai na variável {nome} dos textos ao cliente. |
confirmar_cliente | booleano | não | Envia na hora a confirmação ao cliente pelo WhatsApp. Sem o parâmetro, vale o padrão do tipo (como no formulário da tela); sem tipo, não envia. Mande false para não enviar mesmo num tipo que pede confirmação. |
curl -s -X POST "https://atendimento.seuprovedor.com.br/api_publica.php?r=agenda/criar" \
-H "Authorization: Bearer $CHATISP_CHAVE" \
-H "Content-Type: application/json" \
-d '{"titulo": "Visita técnica: troca de roteador", "tipo_id": 3, "inicio": "2026-10-02T09:00:00-03:00", "local": "Rua das Palmeiras, 120, Centro", "responsavel_id": 7, "departamento_id": 3, "telefone": "44999990000", "nome_cliente": "Maria Souza", "confirmar_cliente": true}'<?php
$dados = [
'titulo' => 'Visita técnica: troca de roteador',
'tipo_id' => 3,
'inicio' => '2026-10-02T09:00:00-03:00',
'local' => 'Rua das Palmeiras, 120, Centro',
'responsavel_id' => 7,
'departamento_id' => 3,
'telefone' => '44999990000',
'nome_cliente' => 'Maria Souza',
'confirmar_cliente' => true,
];
$ch = curl_init('https://atendimento.seuprovedor.com.br/api_publica.php?r=agenda/criar');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('CHATISP_CHAVE'),
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode($dados, JSON_UNESCAPED_UNICODE),
]);
$resposta = json_decode(curl_exec($ch), true);import os, requests
resposta = requests.post(
"https://atendimento.seuprovedor.com.br/api_publica.php",
params={"r": "agenda/criar"},
headers={"Authorization": "Bearer " + os.environ["CHATISP_CHAVE"]},
json={"titulo": "Visita técnica: troca de roteador", "tipo_id": 3, "inicio": "2026-10-02T09:00:00-03:00", "local": "Rua das Palmeiras, 120, Centro", "responsavel_id": 7, "departamento_id": 3, "telefone": "44999990000", "nome_cliente": "Maria Souza", "confirmar_cliente": True},
timeout=30,
).json(){
"ok": true,
"compromisso": {
"id": 342,
"titulo": "Visita técnica: troca de roteador",
"inicio": "2026-10-02T09:00:00-03:00",
"fim": "2026-10-02T10:00:00-03:00",
"estado": "agendado",
"origem": "api",
"...": "demais campos do objeto compromisso"
}
}Como o fim é calculado
- Com
dia_inteiro: do começo ao fim do dia deinicio. - Com
fim: vale o informado. Fim igual ou anterior ao início dáperiodo_invalido. - Com
duracao_min: início mais a duração. - Sem nenhum dos três: início mais a duração padrão do tipo (no mínimo 15 minutos); sem tipo, 60 minutos.
Um compromisso pode durar no máximo 30 dias.
O que acontece ao marcar
- Alertas programados: as antecedências do aviso ao responsável e do lembrete ao cliente vêm do tipo. Sem tipo, o responsável é avisado 15 minutos antes e o cliente não recebe lembrete. Só são programados os alertas cujo horário ainda está no futuro. Detalhes em Alertas e lembretes.
- Aviso ao responsável: a pessoa responsável recebe pelo WhatsApp "Compromisso marcado para você", com data, hora, cliente, local e link. Sem responsável, o aviso vai para a equipe do departamento. Vale para quem tem o WhatsApp verificado e os avisos ligados em Minha conta.
- Confirmação ao cliente: com
confirmar_cliente(ou, sem o parâmetro, quando o tipo pede confirmação), o cliente recebe na hora o texto de confirmação configurado em Configurações (com as variáveis{nome},{data},{hora},{detalhes}e as demais). A mensagem sai pelo atendimento vinculado, pela conversa mais recente com o número ou, sem conversa nenhuma, como mensagem avulsa pelo número conectado. Com o texto de confirmação vazio em Configurações, nada é enviado. Veja Textos enviados ao cliente. - Google Agenda: se a pessoa responsável conectou a conta Google em Minha conta, o compromisso é espelhado na agenda Google dela; se o tipo pede sala do Google Meet e o
linkveio vazio, a sala é criada e o endereço entra no campolinkantes da confirmação e do aviso saírem. Falha no Google nunca impede a marcação: o sistema tenta de novo em segundo plano. - Atendimento vinculado: com
conversa_id, a linha do tempo do atendimento registra o compromisso e, se o atendimento estiver aberto, ganha uma nota interna com título, data e hora. O cliente não vê a nota.
Como na tela, onde a chave Enviar confirmação ao cliente agora já vem ligada nos tipos que pedem confirmação, a API segue o tipo quando confirmar_cliente não é enviado. Os lembretes programados pelo tipo saem normalmente, com ou sem confirmação.
A Agenda não tem eventos de webhook. Para manter um sistema externo em dia, consulte agenda/listar periodicamente pelo período que interessa.
Concluir
/api_publica.php?r=agenda/concluirMarca o compromisso como realizado e registra o desfecho. Só vale para compromisso agendado; em outro estado, a resposta é 409 estado_invalido com o estado atual.
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
id | inteiro | sim | Id do compromisso. |
desfecho | texto | não | O que aconteceu, até 2.000 caracteres. |
curl -s -X POST "https://atendimento.seuprovedor.com.br/api_publica.php?r=agenda/concluir" \
-H "Authorization: Bearer $CHATISP_CHAVE" \
-H "Content-Type: application/json" \
-d '{"id": 342, "desfecho": "Roteador trocado, Wi-Fi testado com a cliente."}'<?php
$dados = [
'id' => 342,
'desfecho' => 'Roteador trocado, Wi-Fi testado com a cliente.',
];
$ch = curl_init('https://atendimento.seuprovedor.com.br/api_publica.php?r=agenda/concluir');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('CHATISP_CHAVE'),
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode($dados, JSON_UNESCAPED_UNICODE),
]);
$resposta = json_decode(curl_exec($ch), true);import os, requests
resposta = requests.post(
"https://atendimento.seuprovedor.com.br/api_publica.php",
params={"r": "agenda/concluir"},
headers={"Authorization": "Bearer " + os.environ["CHATISP_CHAVE"]},
json={"id": 342, "desfecho": "Roteador trocado, Wi-Fi testado com a cliente."},
timeout=30,
).json(){
"ok": true,
"compromisso": {
"id": 342,
"estado": "concluido",
"desfecho": "Roteador trocado, Wi-Fi testado com a cliente.",
"...": "demais campos do objeto compromisso"
}
}Os alertas ainda não enviados são descartados. O atendimento vinculado registra a conclusão na linha do tempo e, se estiver aberto, ganha uma nota interna. O espelho no Google Agenda, quando existe, é sincronizado.
Cancelar
/api_publica.php?r=agenda/cancelarCancela o compromisso e registra o motivo. Só vale para compromisso agendado; em outro estado, a resposta é 409 estado_invalido com o estado atual.
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
id | inteiro | sim | Id do compromisso. |
desfecho | texto | não | Motivo do cancelamento, até 2.000 caracteres. |
curl -s -X POST "https://atendimento.seuprovedor.com.br/api_publica.php?r=agenda/cancelar" \
-H "Authorization: Bearer $CHATISP_CHAVE" \
-H "Content-Type: application/json" \
-d '{"id": 342, "desfecho": "Cliente pediu para remarcar para a próxima semana."}'<?php
$dados = [
'id' => 342,
'desfecho' => 'Cliente pediu para remarcar para a próxima semana.',
];
$ch = curl_init('https://atendimento.seuprovedor.com.br/api_publica.php?r=agenda/cancelar');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('CHATISP_CHAVE'),
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode($dados, JSON_UNESCAPED_UNICODE),
]);
$resposta = json_decode(curl_exec($ch), true);import os, requests
resposta = requests.post(
"https://atendimento.seuprovedor.com.br/api_publica.php",
params={"r": "agenda/cancelar"},
headers={"Authorization": "Bearer " + os.environ["CHATISP_CHAVE"]},
json={"id": 342, "desfecho": "Cliente pediu para remarcar para a próxima semana."},
timeout=30,
).json(){
"ok": true,
"compromisso": {
"id": 342,
"estado": "cancelado",
"desfecho": "Cliente pediu para remarcar para a próxima semana.",
"...": "demais campos do objeto compromisso"
}
}Os alertas pendentes são descartados, o evento espelhado no Google Agenda é removido (e com ele a sala do Meet) e o atendimento vinculado registra o cancelamento. O cliente não recebe mensagem automática de cancelamento: se quiser avisá-lo, envie pela rota mensagens/enviar.
A API não remarca nem reabre compromissos. Para remarcar, cancele o atual e marque um novo com o horário certo; se a confirmação estiver ligada, o cliente recebe a nova data.
Erros das rotas da Agenda
Além dos erros comuns a toda a API, descritos em Erros:
error | HTTP | Rotas | Causa |
|---|---|---|---|
permissao | 403 | todas | A chave não tem Consultar agenda (leitura) ou Gerenciar agenda (escrita). O campo escopo diz qual falta. |
parametro_obrigatorio | 400 | consultar, criar, concluir, cancelar | Faltou id ou inicio (veja campo). |
nao_encontrado | 404 | consultar, concluir, cancelar | Nenhum compromisso com esse id. |
tipo_invalido | 400 | criar | Tipo inexistente ou desativado. |
estado_invalido | 409 | concluir, cancelar | O compromisso não está agendado (já foi concluído ou cancelado). O campo estado traz o estado atual. |
titulo_invalido | 400 | criar | Título vazio ou com mais de 160 caracteres. |
data_invalida | 400 | listar, criar | Data que não pôde ser lida (veja campo). Use ISO 8601 ou AAAA-MM-DD HH:MM:SS; palavras como "amanhã" não são aceitas. |
periodo_invalido | 400 | listar, criar | Na listagem: ate antes de de, ou período acima de 366 dias (com maximo_dias). Na marcação: fim igual ou anterior ao início. |
link_invalido | 400 | criar | Link que não começa com http:// ou https://, tem espaço ou passa de 500 caracteres. |
telefone_invalido | 400 | listar, criar | O telefone não é um número de WhatsApp válido. |
parametro_invalido | 400 | listar, criar | estado desconhecido (lista em aceitos), responsável ou departamento inexistente, responsável inativo, descrição acima de 5.000 caracteres, duração acima de 30 dias, número com letras, limite acima de 100. |
{"ok": false, "error": "periodo_invalido", "maximo_dias": 366}