Voltar ao siteITS TIME / DEV

Documentação · Agenda Universal v1

Integre a agenda por webhooks

Receba o espelho dos agendamentos no seu sistema e devolva ao Its Time apenas o resultado do atendimento.

WEBHOOKS BIDIRECIONAISJSONHMAC-SHA256

01 · Comece aqui

Início rápido

A integração tem duas URLs e muitos tipos de evento. O Its Time envia a agenda para o webhook do parceiro; o parceiro envia de volta somente o resultado do atendimento.

1. Crie a conexão

O administrador cadastra a URL do webhook e recebe os segredos.

2. Receba eventos

Valide a assinatura e persista os eventos de forma idempotente.

3. Reporte o resultado

Envie done ou no_show referenciando o appointmentId do Its Time.

Endpoint de retorno
POST https://api.itstime.pro/api/integrations/agenda/v1/connections/{publicConnectionId}/events

02 · Modelo

O Its Time é a autoridade da agenda

Its Time → parceiro

Webhook de sincronização

Envia unidades, profissionais, disponibilidade, pacientes e alterações de agendamento para a URL cadastrada na conexão.

Parceiro → Its Time

Webhook de resultado

Recebe somente appointment.status_reported, com status done ou no_show.

03 · Preparação

Credenciais e ativação

  1. 01O administrador cria a conexão em Conexões → Integrações → Agenda Universal.
  2. 02O administrador informa a URL HTTPS pública que receberá os eventos.
  3. 03O Its Time gera publicConnectionId, inboundSecret e outboundSecret.
  4. 04O administrador executa o teste e ativa a conexão; a ativação inicia a ressincronização inicial.
SegredoUsado porFinalidade
inboundSecretParceiroAssinar eventos enviados ao Its Time.
outboundSecretIts TimeAssinar webhooks enviados ao parceiro.

04 · Segurança

Autenticação HMAC

Todas as requisições usam JSON e os mesmos cabeçalhos de segurança. A assinatura deve ser calculada sobre os bytes exatos que serão enviados.

Regra da assinatura
signature = HMAC-SHA256(secret, timestamp + "." + rawBody)
X-Agenda-Signature: sha256=<hash_hexadecimal>
CabeçalhoRegra
Content-Typeapplication/json
Idempotency-KeyUUID idêntico, byte a byte, ao eventId
X-Agenda-TimestampUnix timestamp em segundos ou milissegundos
X-Agenda-Signaturesha256= seguido do HMAC-SHA256 hexadecimal

05 · Its Time → parceiro

Eventos enviados para seu webhook

Todos os eventos usam a mesma URL. O tipo fica no campo eventType.

eventTypeUso
integration.testTeste de conexão.
unit.upsertedUnidade criada ou atualizada.
professional.upsertedProfissional criado ou atualizado.
availability.upsertedGrade ou exceção de disponibilidade atualizada.
patient.upsertedPaciente criado ou atualizado.
appointment.createdNovo agendamento.
appointment.rescheduledHorário alterado.
appointment.cancelledAgendamento cancelado.
appointment.status_changedStatus alterado no Its Time.

Cada evento de saída inclui publicConnectionId no corpo, coberto pela assinatura HMAC. Use-o para selecionar a base do grupo; dentro dela, relacione unitId ao CNPJ recebido em unit.upserted. Mais de um ID pode apontar para a mesma base.

Envelope outbound
{
  "schemaVersion": "1.0",
  "publicConnectionId": "4f5a39c0d310a4b91f8de2c770a1b2c3d4e5f60718293a4b",
  "eventId": "9c0c3d11-1e3e-4a18-8c19-02ab7c4d2001",
  "eventType": "appointment.created",
  "occurredAt": "2026-09-15T15:00:00Z",
  "resourceVersion": 1,
  "resource": {
    "id": "6f0f3d0f-9db5-4f35-a6e8-0a0c4d0e1001",
    "status": "scheduled",
    "startTime": "2026-09-20T14:00:00Z",
    "endTime": "2026-09-20T14:30:00Z",
    "timezone": "America/Sao_Paulo",
    "durationMinutes": 30,
    "unitId": "7de2e00c-0b1e-4f3a-9c2b-01c8b6d30001",
    "locationName": null,
    "professionalId": "8de2e00c-0b1e-4f3a-9c2b-01c8b6d30001",
    "assignmentId": "9de2e00c-0b1e-4f3a-9c2b-01c8b6d30001",
    "patientId": "0de2e00c-0b1e-4f3a-9c2b-01c8b6d30001",
    "service": {
      "id": "1de2e00c-0b1e-4f3a-9c2b-01c8b6d30001",
      "name": "Consulta",
      "durationMinutes": 30,
      "price": "123.45",
      "currency": "BRL"
    },
    "origin": "api",
    "notes": null,
    "cancelReason": null,
    "metadata": {},
    "updatedAt": "2026-09-15T15:00:00Z"
  }
}

06 · Parceiro → Its Time

Reportar o resultado do atendimento

Envie o evento somente quando o atendimento tiver um resultado final. O baseResourceVersion deve ser a última versão do agendamento que o parceiro conhece.

Endpoint
POST https://api.itstime.pro/api/integrations/agenda/v1/connections/{publicConnectionId}/events
Payload
{
  "schemaVersion": "1.0",
  "eventId": "4b1d2d8a-5bd2-4f4c-9a9e-26a9a0e2d001",
  "eventType": "appointment.status_reported",
  "occurredAt": "2026-09-15T18:00:00Z",
  "resource": {
    "appointmentId": "6f0f3d0f-9db5-4f35-a6e8-0a0c4d0e1001",
    "status": "done",
    "reason": null,
    "reportedAt": "2026-09-15T18:00:00Z",
    "baseResourceVersion": 7,
    "metadata": { "source": "reception" }
  }
}
CampoValores
eventTypeappointment.status_reported
resource.statusdone ou no_show
resource.appointmentIdUUID do agendamento recebido do Its Time
resource.baseResourceVersionÚltima resourceVersion conhecida pelo parceiro

07 · Implementação

Exemplos de envio

Os exemplos abaixo usam o inboundSecret e enviam o mesmo corpo que foi assinado.

cURL / Bash
URL="https://api.itstime.pro/api/integrations/agenda/v1/connections/{publicConnectionId}/events"
SECRET="SEU_INBOUND_SECRET"
TIMESTAMP=$(date +%s)
EVENT_ID="4b1d2d8a-5bd2-4f4c-9a9e-26a9a0e2d001"
BODY='{"schemaVersion":"1.0","eventId":"4b1d2d8a-5bd2-4f4c-9a9e-26a9a0e2d001","eventType":"appointment.status_reported","occurredAt":"2026-09-15T18:00:00Z","resource":{"appointmentId":"6f0f3d0f-9db5-4f35-a6e8-0a0c4d0e1001","status":"done","reason":null,"reportedAt":"2026-09-15T18:00:00Z","baseResourceVersion":7,"metadata":{"source":"reception"}}}'
SIGNATURE=$(printf '%s.%s' "$TIMESTAMP" "$BODY" | openssl dgst -sha256 -hmac "$SECRET" -hex | sed 's/^.* //')

curl --request POST "$URL"   --header "Content-Type: application/json"   --header "Idempotency-Key: $EVENT_ID"   --header "X-Agenda-Timestamp: $TIMESTAMP"   --header "X-Agenda-Signature: sha256=$SIGNATURE"   --data-raw "$BODY"
Node.js 18+
import { createHmac, randomUUID } from "node:crypto";

const url = "https://api.itstime.pro/api/integrations/agenda/v1/connections/{publicConnectionId}/events";
const secret = process.env.AGENDA_INBOUND_SECRET;
const eventId = randomUUID();
const timestamp = Math.floor(Date.now() / 1000).toString();
const payload = {
  schemaVersion: "1.0",
  eventId,
  eventType: "appointment.status_reported",
  occurredAt: new Date().toISOString(),
  resource: {
    appointmentId: "6f0f3d0f-9db5-4f35-a6e8-0a0c4d0e1001",
    status: "no_show",
    reason: "Paciente não compareceu",
    reportedAt: new Date().toISOString(),
    baseResourceVersion: 7,
    metadata: { source: "reception" }
  }
};
const rawBody = JSON.stringify(payload);
const signature = createHmac("sha256", secret)
  .update(`${timestamp}.${rawBody}`)
  .digest("hex");

const response = await fetch(url, {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "Idempotency-Key": eventId,
    "X-Agenda-Timestamp": timestamp,
    "X-Agenda-Signature": `sha256=${signature}`
  },
  body: rawBody
});

console.log(response.status, await response.text());
Python 3.10+
import hashlib
import hmac
import json
import os
import time
import uuid
import requests

event_id = str(uuid.uuid4())
timestamp = str(int(time.time()))
payload = {
    "schemaVersion": "1.0",
    "eventId": event_id,
    "eventType": "appointment.status_reported",
    "occurredAt": "2026-09-15T18:00:00Z",
    "resource": {
        "appointmentId": "6f0f3d0f-9db5-4f35-a6e8-0a0c4d0e1001",
        "status": "done",
        "reason": None,
        "reportedAt": "2026-09-15T18:00:00Z",
        "baseResourceVersion": 7,
        "metadata": {"source": "reception"},
    },
}
raw_body = json.dumps(payload, ensure_ascii=False, separators=(",", ":")).encode("utf-8")
digest = hmac.new(
    os.environ["AGENDA_INBOUND_SECRET"].encode("utf-8"),
    timestamp.encode("ascii") + b"." + raw_body,
    hashlib.sha256,
).hexdigest()

response = requests.post(
    "https://api.itstime.pro/api/integrations/agenda/v1/connections/{publicConnectionId}/events",
    data=raw_body,
    headers={
        "Content-Type": "application/json",
        "Idempotency-Key": event_id,
        "X-Agenda-Timestamp": timestamp,
        "X-Agenda-Signature": f"sha256={digest}",
    },
    timeout=10,
)
print(response.status_code, response.text)

08 · Operação

Respostas, erros e retentativas

202 Accepted
{
  "accepted": true,
  "duplicate": false,
  "eventId": "4b1d2d8a-5bd2-4f4c-9a9e-26a9a0e2d001",
  "resourceVersion": 8
}
HTTPSignificadoAção
200Evento desconhecido ou recibo já concluído.Não repetir sem necessidade.
202Evento aceito ou duplicado idempotente.Marcar como entregue.
400JSON, cabeçalho ou Idempotency-Key inválido.Corrigir antes de repetir.
401Conexão, timestamp ou assinatura inválidos.Revisar segredo, relógio e corpo bruto.
404Agendamento não encontrado na conexão.Não adivinhar por telefone/data.
409Idempotência em conflito ou resourceVersion obsoleta.Reconciliar o espelho.
413Corpo acima do limite de 64 KiB.Reduzir o payload antes de repetir.
415Content-Type diferente de application/json.Enviar como application/json.
422Transição de status inválida.Corrigir o estado enviado.
429Limite excedido.Respeitar Retry-After.
503Conexão pausada ou indisponível.Repetir com backoff.

Para o webhook do parceiro, o Its Time repete respostas 408, 425, 429 e 5xx, além de falhas de rede. Use o mesmo eventId e o mesmo corpo ao repetir; gere apenas novo timestamp e assinatura.

09 · Referência

Swagger e contratos

Explore os dois sentidos da integração abaixo. O botão de execução está desativado para evitar chamadas reais com credenciais de produção.

10 · Finalização

Checklist de ativação

  • URL pública usando HTTPS.
  • Segredos guardados em gerenciador seguro.
  • HMAC calculado sobre o corpo bruto.
  • eventId persistido para idempotência.
  • Eventos e campos desconhecidos ignorados.
  • resourceVersion controlada.
  • Idempotency-Key igual ao eventId no retorno.
  • done e no_show enviados somente após o atendimento.
  • Backoff configurado para falhas temporárias.
  • Teste concluído antes da ativação.