Ordens de serviço

Referência das oito rotas de ordens de serviço da API do ChatISP: consulte etapas e tipos do quadro, liste e acompanhe ordens de serviço com a linha do tempo completa, e abra, mova, atribua e comente ordens de serviço a partir do seu ERP, do sistema de monitoramento ou do portal do assinante.

Visão geral

OS é a demanda interna da equipe do provedor: visita técnica, reparo de rede, instalação, ajuste financeiro. Ele vive no quadro de Ordens de serviço do painel, passa por etapas até ser resolvido ou cancelado e pode estar ligado a um atendimento do WhatsApp. Pela API, outro sistema enxerga e opera o mesmo quadro, com as mesmas regras do painel: prazo, avisos à equipe, rastro no atendimento de origem e webhooks.

Casos típicos de integração:

  • Monitoramento e NOC: o sistema que detecta a queda de um cliente corporativo ou de uma caixa de atendimento abre a OS de reparo já com prioridade, endereço e descrição técnica.
  • ERP: a ordem de serviço criada no ERP vira OS no quadro da equipe, e a conclusão no ChatISP volta para o ERP pelo webhook.
  • Equipe de campo: o aplicativo do técnico move a OS para a etapa de execução, comenta o que foi feito e marca como resolvido.
  • Painel próprio e BI: listagem de atrasados, ordens de serviço por responsável e sincronização incremental pelo marco de atualização.

Rotas

RotaMétodoPermissão da chaveO que faz
tickets/etapasGETConsultar ordens de serviçoEtapas do quadro, com a natureza de cada uma.
tickets/tiposGETConsultar ordens de serviçoTipos de OS, com prioridade e prazo padrão.
tickets/listarGETConsultar ordens de serviçoLista paginada com filtros.
tickets/consultarGETConsultar ordens de serviçoUma OS com a linha do tempo inteira.
tickets/criarPOSTGerenciar ordens de serviçoAbre uma OS.
tickets/moverPOSTGerenciar ordens de serviçoLeva a OS para outra etapa.
tickets/atribuirPOSTGerenciar ordens de serviçoDefine ou retira o responsável.
tickets/comentarPOSTGerenciar ordens de serviçoComenta na linha do tempo.

A permissão é marcada na chave, em Integrações, card API do ChatISP. Gerenciar ordens de serviço não inclui a leitura: para abrir uma OS e depois acompanhá-lo, marque as duas. Autenticação, formato das chamadas, paginação e erros comuns a todas as rotas estão na Introdução.

Quem aparece como autor

A chave de API não é um usuário da equipe. Por isso, nas ações feitas pela API:

  • O OS aberta pela API nasce com origem igual a api e, na linha do tempo, ganha um evento de sistema com o texto API: <nome da chave>, logo depois do evento de abertura.
  • Comentários entram com o prefixo [API: <nome da chave>] no texto, para a equipe saber de onde vieram.
  • Mudanças de etapa feitas pela API registram no evento o texto [API: <nome da chave>], seguido do comentário quando houver.
  • Os eventos registrados pela API têm autor_id nulo e autor vazio; a origem fica no texto.
  • As notas que a OS deixa no atendimento vinculado citam a chave como autora (por exemplo, "movido para a etapa Em execução por API: ERP").

Dê à chave um nome que a equipe reconheça, como ERP, NOC ou App de campo. É esse nome que aparece no quadro, na linha do tempo e no atendimento.

Visão da casa inteira

A chave enxerga todos as ordens de serviço, de todos os departamentos e responsáveis. As regras de visibilidade dos perfis de acesso (quem vê só as ordens de serviço da própria equipe) valem para as pessoas no painel, não para a API.


O objeto OS

Todas as rotas que devolvem uma OS usam o mesmo formato. Datas em ISO 8601 com fuso; campo sem valor vem null (datas, ids) ou texto vazio (nomes).

CampoTipoDescrição
idinteiroIdentificador interno da OS. Use nas chamadas como ticket_id.
numerotextoNúmero que a equipe vê no quadro, no formato OS-000128. Também serve para localizar a OS nas chamadas (parâmetro numero).
titulotextoTítulo curto, até 160 caracteres.
descricaotextoDescrição livre; vazia quando não foi preenchida.
tipoobjeto ou null{"id", "nome"} do tipo de OS; null quando a OS não tem tipo.
etapaobjeto{"id", "nome", "natureza"} da etapa atual. A natureza diz como o sistema trata a etapa: veja Naturezas, prioridades e prazo.
concluidobooleanotrue quando a etapa atual é final (natureza resolvido ou cancelado).
prioridadetextobaixa, normal, alta ou urgente.
origemtextoDe onde a OS veio: manual (aberto no quadro), chat (aberto a partir de um atendimento), ia (aberto pela IA), copiloto (aberto pelo Copiloto) ou api.
conversa_idinteiro ou nullAtendimento vinculado, quando existe.
protocolotexto ou nullProtocolo do atendimento vinculado.
clienteobjeto{"telefone", "nome", "endereco"}. Telefone com DDI, só dígitos. Os três podem vir vazios em OS interna, sem cliente.
departamento_id / departamentointeiro ou null / textoEquipe dona da OS.
responsavel_id / responsavelinteiro ou null / textoPessoa responsável. null e vazio quando a OS está sem dono.
prazo_emdata ou nullPrazo para resolver. null quando a OS não tem prazo.
prazo_situacaotextosem_prazo, ok, atencao, vencido ou concluido. Calculado no momento da chamada.
resumo_iatexto ou nullResumo do atendimento vinculado feito pela IA para quem vai executar a OS. Chega alguns instantes depois da abertura; null enquanto não existe ou quando não há atendimento vinculado.
total_comentariosinteiroQuantidade de comentários na linha do tempo.
total_anexosinteiroQuantidade de arquivos anexados pela equipe.
erpobjeto ou nullA OS no ERP do provedor (veja No ERP do provedor na documentação do sistema). null quando a OS não tem cliente do ERP vinculado nem registro em ERP algum. Traz erp_id (ERP do cliente vinculado, ou null), id_externo_cliente e id_externo_contrato (identificadores do cliente e do contrato no ERP, texto ou null) e ordens, a lista das OS abertas no ERP para esta OS: zero ou uma por ERP, com os campos da tabela seguinte.
aberto_emdataQuando a OS foi aberto.
iniciado_emdata ou nullPrimeira vez que a OS entrou numa etapa de natureza andamento.
resolvido_emdata ou nullQuando entrou numa etapa resolvido.
fechado_emdata ou nullQuando entrou numa etapa final (resolvido ou cancelado).
ultima_atividade_emdataÚltimo registro na linha do tempo (abertura, etapa, comentário, anexo, edição, resumo). É o campo usado pelo filtro atualizados_desde e pela ordem da listagem.

Campos de erp.ordens[]

CampoTipoDescrição
erp_id / erpinteiro / textoIdentificador e nome do ERP, como cadastrado em Integrações.
tipo_erptextoixc, hubsoft, sgp, gesprov ou pipesoft.
idtextoIdentificador interno da OS no ERP.
numerotextoNúmero da OS como o ERP mostra para a equipe de lá.
protocolotexto ou nullProtocolo da ocorrência ou do chamado, nos ERPs que trabalham com protocolo além do número.
situacaotextoSituação no vocabulário comum do ChatISP: aberta, em_analise, agendada, em_execucao, aguardando, concluida ou desconhecida (o ERP devolveu algo que o ChatISP não reconhece).
situacao_erptexto ou nullA situação crua, como o ERP a chama.
tecnicotexto ou nullTécnico atribuído no ERP, quando informado.
agendado_em / concluido_emdata ou nullAgendamento e conclusão lidos do ERP.
reaproveitadabooleanotrue quando a OS daqui foi ligada a uma OS que já estava aberta no ERP para o mesmo cliente e tipo, em vez de abrir outra.
acompanhabooleanotrue quando o ChatISP consulta o ERP periodicamente e conclui a OS daqui quando o ERP conclui; false no Gesprov, que só permite abrir.
ultima_consulta_emdata ou nullÚltima consulta ao ERP com sucesso.
JSON (objeto OS)
{
  "id": 128,
  "numero": "OS-000128",
  "titulo": "Sem sinal na Rua das Palmeiras",
  "descricao": "ONU sem luz PON desde 09:40. Cliente informa que o vizinho também está sem internet.",
  "tipo": {"id": 2, "nome": "Reparo de rede"},
  "etapa": {"id": 1, "nome": "Aberto", "natureza": "inicial"},
  "concluido": false,
  "prioridade": "urgente",
  "origem": "api",
  "conversa_id": 5310,
  "protocolo": "20261001-0042",
  "cliente": {
    "telefone": "5544999990000",
    "nome": "Maria Souza",
    "endereco": "Rua das Palmeiras, 120, Centro"
  },
  "departamento_id": 3,
  "departamento": "Suporte técnico",
  "responsavel_id": null,
  "responsavel": "",
  "prazo_em": "2026-10-01T18:15:00-03:00",
  "prazo_situacao": "ok",
  "resumo_ia": null,
  "total_comentarios": 0,
  "total_anexos": 0,
  "erp": {
    "erp_id": 1,
    "id_externo_cliente": "8841",
    "id_externo_contrato": "9120",
    "ordens": [
      {
        "erp_id": 1,
        "erp": "IXC Provedor",
        "tipo_erp": "ixc",
        "id": "4521",
        "numero": "4521",
        "protocolo": null,
        "situacao": "aberta",
        "situacao_erp": "A",
        "tecnico": null,
        "agendado_em": null,
        "concluido_em": null,
        "reaproveitada": false,
        "acompanha": true,
        "ultima_consulta_em": "2026-10-01T10:15:05-03:00"
      }
    ]
  },
  "aberto_em": "2026-10-01T10:15:00-03:00",
  "iniciado_em": null,
  "resolvido_em": null,
  "fechado_em": null,
  "ultima_atividade_em": "2026-10-01T10:15:00-03:00"
}

Naturezas, prioridades e prazo

As etapas do quadro têm nome e cor livres, configurados por cada provedor. O que o sistema entende de cada uma é a natureza. Integre sempre pela natureza, nunca pelo nome: "Resolvido" num provedor pode ser "Finalizado" em outro.

Naturezas de etapa

NaturezaRótulo no painelO que o sistema faz
inicialInicial (entrada)Onde a OS nasce. O OS nova entra na primeira etapa ativa de natureza inicial (pela ordem do quadro); sem nenhuma, na primeira etapa ativa.
andamentoEm andamentoA primeira entrada numa etapa assim grava iniciado_em.
aguardandoAguardando terceirosOS parado à espera de algo externo (cliente, fornecedor). O prazo continua correndo.
resolvidoFinal: resolvidoEtapa final: grava resolvido_em e fechado_em, para o prazo e avisa quem abriu a OS.
canceladoFinal: canceladoEtapa final: grava fechado_em, para o prazo e avisa quem abriu a OS.

Tirar uma OS de uma etapa final para uma etapa não final é uma reabertura: resolvido_em e fechado_em voltam a null, o prazo volta a correr e a linha do tempo registra um evento reaberto.

Prioridades

ValorRótulo no painel
baixaBaixa
normalNormal
altaAlta
urgenteUrgente

Na abertura sem prioridade, vale a prioridade padrão do tipo; sem tipo, normal.

Situação do prazo

prazo_situacaoQuando
sem_prazoOS aberta sem prazo definido.
okPrazo no futuro, com folga.
atencaoFaltam 2 horas ou menos, ou menos de 25% do tempo total entre a abertura e o prazo.
vencidoO prazo passou e a OS não está numa etapa final.
concluidoA OS está numa etapa final: o prazo deixou de correr.

Quando o prazo vence com a OS ainda aberto, o sistema registra uma única vez o evento de sistema "Prazo vencido sem conclusão." na linha do tempo e avisa pelo WhatsApp o responsável (ou a equipe do departamento, se a OS estiver sem dono). Esse evento atualiza ultima_atividade_em.


Etapas do quadro

GET/api_publica.php?r=tickets/etapas

Devolve todas as etapas do quadro, na ordem das colunas, inclusive as desativadas. Sem parâmetros. Use para descobrir o etapa_id que tickets/mover pede, sempre escolhendo pela natureza.

Campo de etapas[]Descrição
idIdentificador da etapa.
nomeNome da coluna no quadro.
naturezainicial, andamento, aguardando, resolvido ou cancelado.
corCor da coluna em hexadecimal.
ativafalse quando a etapa foi desativada. Etapa desativada não aceita OS novas nem movimentação.
curl
curl -s -G "https://atendimento.seuprovedor.com.br/api_publica.php" \
  -H "Authorization: Bearer $CHATISP_CHAVE" \
  --data-urlencode "r=tickets/etapas"
PHP
<?php
$url = 'https://atendimento.seuprovedor.com.br/api_publica.php?' . http_build_query([
    'r' => 'tickets/etapas',
]);
$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);
Python
import os, requests

resposta = requests.get(
    "https://atendimento.seuprovedor.com.br/api_publica.php",
    params={"r": "tickets/etapas"},
    headers={"Authorization": "Bearer " + os.environ["CHATISP_CHAVE"]},
    timeout=30,
).json()
Resposta
{
  "ok": true,
  "etapas": [
    {"id": 1, "nome": "Aberto", "natureza": "inicial", "cor": "#38bdf8", "ativa": true},
    {"id": 2, "nome": "Em análise", "natureza": "andamento", "cor": "#8b5cf6", "ativa": true},
    {"id": 3, "nome": "Em execução", "natureza": "andamento", "cor": "#f59e0b", "ativa": true},
    {"id": 4, "nome": "Aguardando cliente", "natureza": "aguardando", "cor": "#64748b", "ativa": true},
    {"id": 5, "nome": "Resolvido", "natureza": "resolvido", "cor": "#10b981", "ativa": true},
    {"id": 6, "nome": "Cancelado", "natureza": "cancelado", "cor": "#d23939", "ativa": true}
  ]
}

Os ids mudam de uma instalação para outra e o provedor pode criar, renomear e reordenar etapas. Guarde em cache por algumas horas e consulte de novo se receber etapa_invalida.


Tipos de OS

GET/api_publica.php?r=tickets/tipos

Devolve os tipos de OS cadastrados em Configurações do módulo, inclusive os desativados. Sem parâmetros. O tipo define a prioridade, o prazo e a equipe que a OS recebe quando a chamada de abertura não informa esses campos.

Campo de tipos[]Descrição
idIdentificador do tipo, usado em tipo_id.
nomeNome do tipo.
ativofalse quando desativado. Tipo desativado é recusado na abertura (tipo_invalido).
prioridade_padraoPrioridade aplicada quando a abertura não informa uma.
prazo_horasHoras até o prazo, contadas da abertura. 0 significa sem prazo automático.
departamento_idEquipe que recebe a OS quando a abertura não informa departamento_id; null se o tipo não tem equipe.
curl
curl -s -G "https://atendimento.seuprovedor.com.br/api_publica.php" \
  -H "Authorization: Bearer $CHATISP_CHAVE" \
  --data-urlencode "r=tickets/tipos"
PHP
<?php
$url = 'https://atendimento.seuprovedor.com.br/api_publica.php?' . http_build_query([
    'r' => 'tickets/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);
Python
import os, requests

resposta = requests.get(
    "https://atendimento.seuprovedor.com.br/api_publica.php",
    params={"r": "tickets/tipos"},
    headers={"Authorization": "Bearer " + os.environ["CHATISP_CHAVE"]},
    timeout=30,
).json()
Resposta
{
  "ok": true,
  "tipos": [
    {"id": 1, "nome": "Visita técnica", "ativo": true, "prioridade_padrao": "alta", "prazo_horas": 24, "departamento_id": 3},
    {"id": 2, "nome": "Reparo de rede", "ativo": true, "prioridade_padrao": "urgente", "prazo_horas": 8, "departamento_id": 3},
    {"id": 3, "nome": "Instalação", "ativo": true, "prioridade_padrao": "normal", "prazo_horas": 48, "departamento_id": null},
    {"id": 4, "nome": "Financeiro", "ativo": true, "prioridade_padrao": "normal", "prazo_horas": 24, "departamento_id": 2},
    {"id": 5, "nome": "Outro", "ativo": true, "prioridade_padrao": "normal", "prazo_horas": 24, "departamento_id": null}
  ]
}

Listar ordens de serviço

GET/api_publica.php?r=tickets/listar

Lista paginada de ordens de serviço, do mais recentemente movimentado para o mais antigo (ordem de ultima_atividade_em). Todos os filtros são opcionais e se combinam (todos precisam valer ao mesmo tempo). Sem filtro, vêm todos as ordens de serviço, abertos e concluídos.

ParâmetroTipoDescrição
situacaotextotodos (padrão), abertos (etapa não final) ou concluidos (resolvidos e cancelados).
etapa_idinteiroSó as ordens de serviço dessa etapa.
tipo_idinteiroSó os desse tipo.
departamento_idinteiroSó os dessa equipe.
conversa_idinteiroSó os vinculados a esse atendimento.
responsavel_idinteiroSó os dessa pessoa. Com 0, só as ordens de serviço sem dono.
prioridadetextobaixa, normal, alta ou urgente.
atrasadosbooleano1 (ou true): só os OS abertas com prazo vencido.
telefonetextoSó os do cliente desse número. Mesma regra de telefone do resto da API (sem +, é brasileiro); o número é procurado com e sem o nono dígito.
abertos_desde / abertos_atedataFaixa da data de abertura. Data sem hora em abertos_ate vale até 23:59:59 do dia.
atualizados_desdedataSó os que tiveram qualquer registro na linha do tempo a partir desse instante. Base da sincronização incremental.
buscatextoProcura no número, título, descrição, nome do cliente e endereço (até 120 caracteres).
pagina / limiteinteiroPaginação numerada: limite de 1 a 100 (padrão 50).
curl
curl -s -G "https://atendimento.seuprovedor.com.br/api_publica.php" \
  -H "Authorization: Bearer $CHATISP_CHAVE" \
  --data-urlencode "r=tickets/listar" \
  --data-urlencode "situacao=abertos" \
  --data-urlencode "departamento_id=3" \
  --data-urlencode "atrasados=1" \
  --data-urlencode "limite=20"
PHP
<?php
$url = 'https://atendimento.seuprovedor.com.br/api_publica.php?' . http_build_query([
    'r' => 'tickets/listar',
    'situacao' => 'abertos',
    'departamento_id' => 3,
    'atrasados' => '1',
    'limite' => 20,
]);
$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);
Python
import os, requests

resposta = requests.get(
    "https://atendimento.seuprovedor.com.br/api_publica.php",
    params={"r": "tickets/listar", "situacao": "abertos", "departamento_id": 3, "atrasados": "1", "limite": 20},
    headers={"Authorization": "Bearer " + os.environ["CHATISP_CHAVE"]},
    timeout=30,
).json()
Resposta
{
  "ok": true,
  "tickets": [
    {
      "id": 121,
      "numero": "OS-000121",
      "titulo": "Troca de conector na CTO 14",
      "etapa": {"id": 3, "nome": "Em execução", "natureza": "andamento"},
      "concluido": false,
      "prioridade": "alta",
      "responsavel_id": 7,
      "responsavel": "Carlos Lima",
      "prazo_em": "2026-10-01T08:00:00-03:00",
      "prazo_situacao": "vencido",
      "ultima_atividade_em": "2026-10-01T09:12:44-03:00",
      "...": "demais campos do objeto ticket"
    }
  ],
  "paginacao": {"pagina": 1, "limite": 20, "total": 1, "paginas": 1}
}

Sincronização incremental

Para manter um espelho das ordens de serviço no seu sistema, guarde o instante de cada rodada e, na seguinte, peça atualizados_desde com esse instante (de preferência com alguns minutos de folga, gravando por id para não duplicar). Abertura, mudança de etapa, troca de responsável, comentário, anexo, edição, resumo da IA e prazo vencido atualizam o marco. A hora certa do servidor está em servidor.agora da rota chave/info.

Se o seu sistema só precisa reagir quando algo muda, o webhook é mais eficiente que consultar de tempos em tempos: os eventos ticket_criado e ticket_atualizado chegam na hora. Veja Webhooks.


Consultar uma OS

GET/api_publica.php?r=tickets/consultar

Devolve a OS e a linha do tempo completa, do evento mais antigo para o mais recente.

ParâmetroTipoObrigatórioDescrição
ticket_idinteiroum dos doisId da OS (também aceito como id).
numerotextoum dos doisNúmero da OS, como OS-000128. Útil quando o número foi digitado por uma pessoa.
curl
curl -s -G "https://atendimento.seuprovedor.com.br/api_publica.php" \
  -H "Authorization: Bearer $CHATISP_CHAVE" \
  --data-urlencode "r=tickets/consultar" \
  --data-urlencode "numero=T-000128"
PHP
<?php
$url = 'https://atendimento.seuprovedor.com.br/api_publica.php?' . http_build_query([
    'r' => 'tickets/consultar',
    'numero' => 'OS-000128',
]);
$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);
Python
import os, requests

resposta = requests.get(
    "https://atendimento.seuprovedor.com.br/api_publica.php",
    params={"r": "tickets/consultar", "numero": "OS-000128"},
    headers={"Authorization": "Bearer " + os.environ["CHATISP_CHAVE"]},
    timeout=30,
).json()
Resposta
{
  "ok": true,
  "ticket": {"id": 128, "numero": "OS-000128", "...": "objeto ticket completo"},
  "eventos": [
    {
      "id": 901, "tipo": "aberto", "autor_id": null, "autor": "", "texto": "",
      "dados": {"origem": "api", "etapa": "Aberto"}, "anexos": [],
      "criado_em": "2026-10-01T10:15:00-03:00"
    },
    {
      "id": 902, "tipo": "sistema", "autor_id": null, "autor": "", "texto": "API: NOC",
      "dados": [], "anexos": [], "criado_em": "2026-10-01T10:15:00-03:00"
    },
    {
      "id": 910, "tipo": "responsavel", "autor_id": 4, "autor": "Paula Andrade", "texto": "",
      "dados": {"de": null, "de_nome": "", "para": 7, "para_nome": "Carlos Lima"}, "anexos": [],
      "criado_em": "2026-10-01T10:31:20-03:00"
    },
    {
      "id": 915, "tipo": "etapa", "autor_id": 7, "autor": "Carlos Lima", "texto": "Equipe a caminho",
      "dados": {"de": 1, "de_nome": "Aberto", "de_cor": "#38bdf8", "para": 3, "para_nome": "Em execução",
                "para_cor": "#f59e0b", "natureza": "andamento"},
      "anexos": [], "criado_em": "2026-10-01T10:40:02-03:00"
    },
    {
      "id": 921, "tipo": "comentario", "autor_id": 7, "autor": "Carlos Lima",
      "texto": "Fibra rompida no poste 32. Emenda feita, sinal normalizado.",
      "dados": [], "anexos": [{"nome": "emenda.jpg", "tamanho": 284113}],
      "criado_em": "2026-10-01T12:05:51-03:00"
    }
  ]
}
Campo de eventos[]Descrição
idIdentificador do evento (crescente).
tipoTipo do evento: tabela abaixo.
autor_id / autorQuem fez. null e vazio para o sistema, a IA e as ações feitas pela API.
textoTexto do comentário, do resumo da IA, do comentário que acompanhou a mudança de etapa ou da mensagem de sistema.
dadosDetalhes estruturados do evento (objeto); lista vazia quando não há.
anexosArquivos anexados junto com o evento: {"nome", "tamanho"} (tamanho em bytes). O download do anexo é feito pelo painel.
criado_emQuando aconteceu.

Tipos de evento da linha do tempo

tipoQuando apareceConteúdo de dados e texto
abertoAbertura da OS.origem e etapa (nome da etapa inicial).
responsavelResponsável definido, trocado ou retirado; também quando alguém da equipe move uma OS sem dono para uma etapa de trabalho e passa a ser o dono.de, de_nome, para, para_nome. para nulo = OS ficou sem dono.
etapaMudança de etapa.de, de_nome, de_cor, para, para_nome, para_cor, natureza (da etapa de destino). O comentário que acompanhou a mudança vem em texto.
reabertoSaída de uma etapa final para uma etapa não final.Mesmos campos de etapa.
comentarioComentário da equipe ou da API.Texto em texto; arquivos do comentário em anexos.
anexoArquivo anexado sem comentário, enviado do computador ou trazido do atendimento.nome do arquivo, ou origem igual a conversa quando veio do chat.
tipoTipo da OS trocado no painel.de_nome, para_nome.
prioridadePrioridade trocada no painel.de, para.
prazoPrazo trocado no painel.de, para, como texto curto de data e hora (o formato que a tela mostra).
editadoOutros campos editados no painel (título, descrição, cliente, endereço, equipe).campos (lista dos campos alterados) e detalhe.
iaResumo do atendimento vinculado, gerado pela IA.Resumo em texto.
erpO que aconteceu no ERP do provedor: abertura, vínculo a uma OS que já existia, falha ao abrir, mudança de situação, técnico ou agenda, e conclusão.dados.acao (aberta, vinculada, falha, situacao ou concluida), dados.erp_nome, dados.os_numero e, conforme a ação, a situação nova, o técnico, a agenda ou o motivo da falha (erro e mensagem).
sistemaRegistro automático: a marca API: <nome da chave> na abertura pela API, ou "Prazo vencido sem conclusão.".Texto em texto; no prazo vencido, dados.prazo.

Trate tipos de evento desconhecidos sem quebrar a integração: novos tipos podem surgir com a evolução do quadro. Mostre o texto quando houver e ignore o resto.


Abrir uma OS

POST/api_publica.php?r=tickets/criar

Abre uma OS na etapa inicial do quadro. Só o título é obrigatório; o resto completa a OS e, quando omitido, é preenchido pelo tipo ou pelo atendimento vinculado.

ParâmetroTipoObrigatórioDescrição
titulotextosimDe 1 a 160 caracteres.
descricaotextonãoAté 20.000 caracteres. Coloque aqui tudo o que o técnico precisa: sintomas, equipamento, sinal, referências do endereço.
tipo_idinteironãoTipo da OS (ordens de serviço/tipos). Tipo inexistente ou desativado dá tipo_invalido.
prioridadetextonãobaixa, normal, alta ou urgente. Sem ela, vale a do tipo; sem tipo, normal.
prazo_emdatanãoPrazo explícito. Sem ele, o prazo é a abertura mais as prazo_horas do tipo (tipo com 0 = sem prazo); sem tipo, 24 horas.
conversa_idinteironãoAtendimento de origem. Vincula a OS à conversa e completa telefone e nome do cliente quando não informados.
telefonetextonãoWhatsApp do cliente. Mesma regra de telefone do resto da API.
nome_clientetextonãoNome do cliente, até 190 caracteres.
enderecotextonãoEndereço do serviço, até 255 caracteres.
departamento_idinteironãoEquipe dona. Sem ela, vale a equipe do tipo. Departamento inexistente dá departamento_invalido.
responsavel_idinteironãoPessoa responsável (atendentes/listar). Sem ela, a OS nasce sem dono. Usuário inexistente ou inativo dá atendente_invalido.
erp_abrir0 ou 1nãoAbertura da OS também no ERP do provedor. 1 pede a abertura nos tipos com postura Perguntar ao abrir; 0 segura a abertura nos tipos com Sempre: abre no ERP junto. Omitido, vale a postura do tipo (Sempre abre, Perguntar não abre). Só tem efeito com as ordens de serviço ligadas no cartão do ERP, o tipo mapeado para o ERP e um cliente do ERP identificado (pelo conversa_id de um atendimento com assinante reconhecido). O resultado volta em erp.
curl
curl -s -X POST "https://atendimento.seuprovedor.com.br/api_publica.php?r=tickets/criar" \
  -H "Authorization: Bearer $CHATISP_CHAVE" \
  -H "Content-Type: application/json" \
  -d '{"titulo": "Sem sinal na Rua das Palmeiras", "descricao": "ONU sem luz PON desde 09:40. Vizinho também sem internet.", "tipo_id": 2, "prioridade": "urgente", "telefone": "44999990000", "nome_cliente": "Maria Souza", "endereco": "Rua das Palmeiras, 120, Centro", "departamento_id": 3}'
PHP
<?php
$dados = [
    'titulo' => 'Sem sinal na Rua das Palmeiras',
    'descricao' => 'ONU sem luz PON desde 09:40. Vizinho também sem internet.',
    'tipo_id' => 2,
    'prioridade' => 'urgente',
    'telefone' => '44999990000',
    'nome_cliente' => 'Maria Souza',
    'endereco' => 'Rua das Palmeiras, 120, Centro',
    'departamento_id' => 3,
];
$ch = curl_init('https://atendimento.seuprovedor.com.br/api_publica.php?r=tickets/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);
Python
import os, requests

resposta = requests.post(
    "https://atendimento.seuprovedor.com.br/api_publica.php",
    params={"r": "tickets/criar"},
    headers={"Authorization": "Bearer " + os.environ["CHATISP_CHAVE"]},
    json={"titulo": "Sem sinal na Rua das Palmeiras", "descricao": "ONU sem luz PON desde 09:40. Vizinho também sem internet.", "tipo_id": 2, "prioridade": "urgente", "telefone": "44999990000", "nome_cliente": "Maria Souza", "endereco": "Rua das Palmeiras, 120, Centro", "departamento_id": 3},
    timeout=30,
).json()

A resposta traz a OS completo no formato do objeto OS:

Resposta
{
  "ok": true,
  "ticket": {
    "id": 128,
    "numero": "OS-000128",
    "titulo": "Sem sinal na Rua das Palmeiras",
    "etapa": {"id": 1, "nome": "Aberto", "natureza": "inicial"},
    "prioridade": "urgente",
    "origem": "api",
    "prazo_em": "2026-10-01T18:15:00-03:00",
    "prazo_situacao": "ok",
    "...": "demais campos do objeto ticket"
  }
}

O que acontece ao abrir

  1. Número e etapa: a OS recebe o número T- e entra na etapa inicial do quadro. A linha do tempo registra o evento aberto (com origem igual a api) e o evento de sistema API: <nome da chave>.
  2. Prazo e prioridade pelo tipo: sem prazo_em e sem prioridade, valem os padrões do tipo. O tipo Reparo de rede de fábrica, por exemplo, dá prioridade urgente e 8 horas de prazo.
  3. Responsável: com responsavel_id válido, a linha do tempo registra o evento responsavel.
  4. Avisos à equipe: com responsável, ele recebe pelo WhatsApp "OS atribuída a você". Sem responsável e com equipe, as pessoas do departamento recebem "Nova OS para a equipe". O aviso pelo WhatsApp vale para quem tem o WhatsApp verificado e os avisos ligados em Minha conta.
  5. Rastro no atendimento vinculado: com conversa_id, a linha do tempo do atendimento ganha o registro da OS (número e título) e, com a IA configurada e o atendimento tendo alguma conversa de fato, a IA prepara o resumo do atendimento para o técnico, que aparece em resumo_ia e como evento ia na linha do tempo da OS. O cliente não vê nada disso.
  6. OS no ERP: conforme a postura do tipo e erp_abrir, a OS é aberta também no ERP do provedor. Antes, o ChatISP confere se o cliente já tem OS aberta do mesmo tipo lá e, se tiver, liga a OS daqui a ela (reaproveitada: true) em vez de abrir outra. Número e situação voltam em erp.ordens; falha ao abrir não impede a criação da OS aqui e fica registrada na linha do tempo como evento erp. Depois, cada mudança no ERP vira um evento erp e dispara ticket_atualizado; a conclusão no ERP move a OS para a etapa de natureza resolvido.
  7. Webhook: sai o evento ticket_criado para os webhooks inscritos nele.

A OS é interno: nada é enviado ao cliente. Para avisar o cliente que a equipe técnica foi acionada, envie uma mensagem pela rota mensagens/enviar. A receita NOC abre OS e avisa o cliente mostra o fluxo completo.


Mover de etapa

POST/api_publica.php?r=tickets/mover

Leva a OS para outra etapa do quadro, com um comentário opcional. É a mesma ação de arrastar o cartão no painel.

ParâmetroTipoObrigatórioDescrição
ticket_id ou numerointeiro / textosimQual OS.
etapa_idinteirosimEtapa de destino (ordens de serviço/etapas). Precisa estar ativa.
comentariotextonãoAté 1.900 caracteres. Fica no evento da mudança de etapa, depois da marca [API: <nome da chave>], e, resumido, na nota do atendimento vinculado.
curl
curl -s -X POST "https://atendimento.seuprovedor.com.br/api_publica.php?r=tickets/mover" \
  -H "Authorization: Bearer $CHATISP_CHAVE" \
  -H "Content-Type: application/json" \
  -d '{"numero": "OS-000128", "etapa_id": 5, "comentario": "Emenda feita no poste 32, sinal normalizado."}'
PHP
<?php
$dados = [
    'numero' => 'OS-000128',
    'etapa_id' => 5,
    'comentario' => 'Emenda feita no poste 32, sinal normalizado.',
];
$ch = curl_init('https://atendimento.seuprovedor.com.br/api_publica.php?r=tickets/mover');
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);
Python
import os, requests

resposta = requests.post(
    "https://atendimento.seuprovedor.com.br/api_publica.php",
    params={"r": "tickets/mover"},
    headers={"Authorization": "Bearer " + os.environ["CHATISP_CHAVE"]},
    json={"numero": "OS-000128", "etapa_id": 5, "comentario": "Emenda feita no poste 32, sinal normalizado."},
    timeout=30,
).json()
Resposta
{
  "ok": true,
  "ticket": {
    "id": 128,
    "numero": "OS-000128",
    "etapa": {"id": 5, "nome": "Resolvido", "natureza": "resolvido"},
    "concluido": true,
    "prazo_situacao": "concluido",
    "resolvido_em": "2026-10-01T12:06:10-03:00",
    "fechado_em": "2026-10-01T12:06:10-03:00",
    "...": "demais campos do objeto ticket"
  }
}

Regras da movimentação

  • A chave não vira dona. No painel, quem move uma OS sem dono para uma etapa de trabalho passa a ser o responsável. Pela API isso não acontece: a OS continua sem dono até alguém assumir ou até você chamar ordens de serviço/atribuir.
  • Mesma etapa: mover para a etapa em que a OS já está não registra nada e devolve a OS como está.
  • Datas: a primeira entrada em etapa andamento grava iniciado_em; etapa resolvido grava resolvido_em e fechado_em; cancelado grava fechado_em. Sair de etapa final é reabertura (evento reaberto).
  • Avisos: ao entrar em etapa final, quem abriu a OS pelo painel recebe aviso pelo WhatsApp. OS abertas pela API não têm uma pessoa como autora, então esse aviso não sai.
  • Atendimento vinculado: enquanto o atendimento estiver aberto, ganha uma nota interna "OS OS-000128 movido para a etapa Resolvido por API: <nome da chave>." seguida do comentário. Atendimento encerrado não recebe nota.
  • Webhook: sai ticket_atualizado com mudanca igual a etapa (ou reaberto).

Para concluir uma OS sem depender do nome da etapa, procure em tickets/etapas a primeira etapa ativa com natureza resolvido e use o id dela.


Atribuir responsável

POST/api_publica.php?r=tickets/atribuir

Define, troca ou retira o responsável pela OS.

ParâmetroTipoObrigatórioDescrição
ticket_id ou numerointeiro / textosimQual OS.
responsavel_idinteirosimId da pessoa (atendentes/listar), que precisa estar ativa. 0 tira o dono: a OS volta a ficar sem responsável.
curl
curl -s -X POST "https://atendimento.seuprovedor.com.br/api_publica.php?r=tickets/atribuir" \
  -H "Authorization: Bearer $CHATISP_CHAVE" \
  -H "Content-Type: application/json" \
  -d '{"ticket_id": 128, "responsavel_id": 7}'
PHP
<?php
$dados = [
    'ticket_id' => 128,
    'responsavel_id' => 7,
];
$ch = curl_init('https://atendimento.seuprovedor.com.br/api_publica.php?r=tickets/atribuir');
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);
Python
import os, requests

resposta = requests.post(
    "https://atendimento.seuprovedor.com.br/api_publica.php",
    params={"r": "tickets/atribuir"},
    headers={"Authorization": "Bearer " + os.environ["CHATISP_CHAVE"]},
    json={"ticket_id": 128, "responsavel_id": 7},
    timeout=30,
).json()
Resposta
{
  "ok": true,
  "ticket": {
    "id": 128,
    "numero": "OS-000128",
    "responsavel_id": 7,
    "responsavel": "Carlos Lima",
    "...": "demais campos do objeto ticket"
  }
}
  • Atribuir à pessoa que já é a responsável não registra nada.
  • A nova pessoa responsável recebe pelo WhatsApp "OS atribuída a você" (se tiver o WhatsApp verificado e os avisos ligados).
  • A linha do tempo registra o evento responsavel; o atendimento vinculado, se aberto, ganha a nota interna correspondente.
  • Sai o webhook ticket_atualizado com mudanca igual a responsavel.

Comentar

POST/api_publica.php?r=tickets/comentar

Acrescenta um comentário na linha do tempo da OS, sem mudar etapa nem responsável. Bom para devolver ao quadro o que aconteceu no seu sistema: OS fechada no ERP, leitura de sinal coletada pelo monitoramento, retorno do fornecedor.

ParâmetroTipoObrigatórioDescrição
ticket_id ou numerointeiro / textosimQual OS.
textotextosimDe 1 a 19.000 caracteres. Gravado com o prefixo [API: <nome da chave>].
curl
curl -s -X POST "https://atendimento.seuprovedor.com.br/api_publica.php?r=tickets/comentar" \
  -H "Authorization: Bearer $CHATISP_CHAVE" \
  -H "Content-Type: application/json" \
  -d '{"numero": "OS-000128", "texto": "Sinal da ONU normalizado: -19,8 dBm às 12:04."}'
PHP
<?php
$dados = [
    'numero' => 'OS-000128',
    'texto' => 'Sinal da ONU normalizado: -19,8 dBm às 12:04.',
];
$ch = curl_init('https://atendimento.seuprovedor.com.br/api_publica.php?r=tickets/comentar');
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);
Python
import os, requests

resposta = requests.post(
    "https://atendimento.seuprovedor.com.br/api_publica.php",
    params={"r": "tickets/comentar"},
    headers={"Authorization": "Bearer " + os.environ["CHATISP_CHAVE"]},
    json={"numero": "OS-000128", "texto": "Sinal da ONU normalizado: -19,8 dBm às 12:04."},
    timeout=30,
).json()
Resposta
{
  "ok": true,
  "evento_id": 933,
  "ticket": {
    "id": 128,
    "numero": "OS-000128",
    "total_comentarios": 2,
    "...": "demais campos do objeto ticket"
  }
}

O atendimento vinculado, se aberto, recebe uma nota interna com o começo do comentário (até 200 caracteres). Sai o webhook ticket_atualizado com mudanca igual a comentario e o campo comentario com até 2.000 caracteres do texto.

Anexar arquivos à OS é uma ação do painel. Pela API, registre o link do arquivo no texto do comentário.


Webhooks de ordens de serviço

Dois eventos cobrem o ciclo da OS, venha a mudança do painel, da IA, do Copiloto ou da própria API:

EventoQuandomudanca
ticket_criadoOS aberta.(não tem)
ticket_atualizadoMudança de etapa, reabertura, troca de responsável ou comentário.etapa, reaberto, responsavel ou comentario (este último com o campo comentario).

O corpo traz um resumo estável da OS em dados: ticket_id, numero, titulo, etapa_id, etapa, natureza, prioridade, origem, conversa_id, telefone, nome_cliente, departamento_id, responsavel_id, responsavel e prazo_em.

Corpo do webhook (ticket_atualizado)
{
  "evento": "ticket_atualizado",
  "emitido_em": "2026-10-01T12:06:10-03:00",
  "dados": {
    "ticket_id": 128,
    "numero": "OS-000128",
    "titulo": "Sem sinal na Rua das Palmeiras",
    "etapa_id": 5,
    "etapa": "Resolvido",
    "natureza": "resolvido",
    "prioridade": "urgente",
    "origem": "api",
    "conversa_id": 5310,
    "telefone": "5544999990000",
    "nome_cliente": "Maria Souza",
    "departamento_id": 3,
    "responsavel_id": 7,
    "responsavel": "Carlos Lima",
    "prazo_em": "2026-10-01T18:15:00-03:00",
    "mudanca": "etapa"
  }
}

Edições feitas no painel (título, tipo, prioridade, prazo, cliente), anexos e o resumo da IA não geram webhook; para elas, use tickets/listar com atualizados_desde. O conteúdo completo está em Dados dos eventos de OS; assinatura, entrega e retentativas, em Webhooks.


Erros das rotas de ordens de serviço

Além dos erros comuns a toda a API (autenticação, permissão, plano, cota, método), descritos em Erros:

errorHTTPRotasCausa
permissao403todasA chave não tem Consultar ordens de serviço (leitura) ou Gerenciar ordens de serviço (escrita). O campo escopo diz qual falta.
identificador_obrigatorio400consultar, mover, atribuir, comentarFaltou ticket_id e numero.
nao_encontrado404consultar, mover, atribuir, comentarNenhum OS com esse id ou número.
titulo_invalido400criarTítulo vazio ou com mais de 160 caracteres.
conversa_invalida400criarconversa_id não existe.
telefone_invalido400criar, listarO telefone não é um número de WhatsApp válido.
sem_etapas409criarO quadro não tem nenhuma etapa ativa para receber a OS.
etapa_invalida400moverEtapa inexistente ou desativada.
parametro_obrigatorio400mover, atribuirFaltou etapa_id ou responsavel_id (veja campo).
tipo_invalido400criarTipo inexistente ou desativado.
departamento_invalido400criarDepartamento inexistente.
atendente_invalido400criar, atribuirUsuário inexistente ou inativo.
texto_invalido400comentarTexto vazio ou acima de 19.000 caracteres.
parametro_invalido400listar, criarValor fora do aceito: situacao ou prioridade desconhecida (a lista vem em aceitos), número com letras, descrição acima de 20.000 caracteres, limite acima de 100.
data_invalida400listar, criarData que não pôde ser lida (veja campo).
Exemplo de erro
{"ok": false, "error": "etapa_invalida"}