API de agendamentos · v1

Documentação da API

A API da Alibit permite que outros sistemas (ERP, site, app, chatbot) leiam e gravem a agenda de uma empresa: profissionais, serviços, horários livres, clientes e agendamentos. Quando algo muda na agenda, avisamos o seu sistema por webhooks.

URL basehttps://api.alibit.com.br/v1
FormatoJSON · UTF-8
AutenticaçãoX-Api-Key

Produção e sandbox

Existe uma única URL para testes e para produção. O que muda é a chave de API: cada chave pertence a uma empresa, e a API só enxerga os dados dela.

Sandbox

Para desenvolver e testar

  • Uma empresa de testes criada para você, com nome Sandbox – sua empresa.
  • Já vem com dados fictícios: 2 profissionais, 5 serviços, 6 clientes e uma semana de agendamentos.
  • Pode criar, alterar e apagar à vontade: nada afeta clientes reais.
  • Mesmos limites e mesmas regras da produção (conflito de horário, expediente, validações).

Peça a sua em contato@alibit.com.br.

Produção

Com a agenda real da empresa

  • A chave é gerada pela própria empresa que usa a Alibit, no painel em Gestão da empresa → Integrações.
  • O plano da empresa precisa incluir API para integrações.
  • A empresa pode revogar a chave a qualquer momento.

Para ir ao ar, troque só a chave: a URL e o código continuam iguais.

Dica: guarde a chave em uma variável de ambiente (ex.: ALIBIT_API_KEY). Assim o mesmo código roda no sandbox e em produção, mudando só a configuração.

Diferenças da empresa de sandbox: ela não tem site de agendamento público e não é cobrada. Todo o resto funciona igual.

Início rápido

Com a chave do sandbox em mãos, confira se ela funciona buscando os dados da empresa:

curl https://api.alibit.com.br/v1/companies/me \
  -H "X-Api-Key: $ALIBIT_API_KEY"

Resposta:

{
  "id": "6f1c…",
  "name": "Sandbox – Sua Empresa",
  "slug": "sandbox-sua-empresa",
  "status": "ACTIVE"
}

Em JavaScript (Node 18+), a mesma chamada:

const res = await fetch('https://api.alibit.com.br/v1/companies/me', {
  headers: { 'X-Api-Key': process.env.ALIBIT_API_KEY },
});
if (!res.ok) throw new Error(`Erro ${res.status}: ${await res.text()}`);
const empresa = await res.json();

Depois, siga o fluxo de agendamento para marcar o primeiro horário.

Autenticação

Envie a chave no cabeçalho X-Api-Key de toda requisição. As chaves começam com agd_.

GET /v1/appointments HTTP/1.1
Host: api.alibit.com.br
X-Api-Key: agd_…
  • A chave age como o administrador da empresa que a criou e só enxerga os dados dessa empresa.
  • Use a chave só no servidor. Nunca a coloque em código que roda no navegador ou no celular do cliente.
  • Chave ausente, inválida ou revogada: resposta 401.
  • Plano sem API para integrações: resposta 403 com "code": "FEATURE_NOT_IN_PLAN".
  • Com a chave não é possível criar outras chaves, cadastrar webhooks nem redefinir senhas: isso é feito no painel.

Limites

LimiteValorAo passar dele
Por minuto120 requisições por chave429 com o cabeçalho Retry-After (segundos)
Por mêsDepende do plano da empresa429 com "code": "API_MONTHLY_QUOTA_EXCEEDED" até o dia 1º do mês seguinte

Quando o plano tem limite mensal, toda resposta traz X-Api-Quota-Limit (total do mês) e X-Api-Quota-Remaining (quanto ainda resta). Planos sem limite mensal não enviam esses cabeçalhos.

Boa prática: em vez de consultar a agenda de tempos em tempos, use webhooks. Você recebe cada mudança na hora e gasta muito menos requisições.

Erros

Os erros vêm em JSON. Alguns trazem um code estável para você tratar no seu sistema; em erros de validação, message é uma lista.

{
  "statusCode": 409,
  "message": "Já existe um agendamento neste horário",
  "error": "Conflict"
}
StatusQuando acontece
400Dados inválidos (campo faltando, formato errado, horário fora do expediente)
401Chave ausente, inválida ou revogada
403Empresa bloqueada (COMPANY_BLOCKED) ou recurso fora do plano (FEATURE_NOT_IN_PLAN)
404Registro não existe ou pertence a outra empresa
409Conflito: horário já ocupado, cliente com telefone ou e-mail repetido
429Limite por minuto ou mensal atingido
5xxErro do nosso lado. Tente de novo com espera crescente (1 s, 2 s, 4 s…)

Datas e fusos

  • Data e hora sempre em ISO 8601, em UTC: 2026-10-09T13:00:00.000Z.
  • Ao enviar, você pode usar UTC (Z) ou informar o fuso: 2026-10-09T10:00:00-03:00 é o mesmo instante.
  • Converta para o fuso da empresa (America/Sao_Paulo) antes de mostrar ao usuário.
  • Datas sem hora, como o aniversário do cliente ou o dia consultado em horários livres, usam YYYY-MM-DD.
  • Horários de expediente usam HH:mm no fuso da empresa; dias da semana vão de 0 (domingo) a 6 (sábado).

Versionamento

Todas as rotas começam com /v1. Campos novos podem aparecer nas respostas a qualquer momento: ignore o que não conhece. Mudanças que quebram compatibilidade vão para uma nova versão (/v2), com aviso prévio, e a v1 continua funcionando.

Fluxo de agendamento

O caminho mais comum para marcar um horário pela sua integração:

  1. Listar profissionais da empresa

    curl https://api.alibit.com.br/v1/team/professionals -H "X-Api-Key: $ALIBIT_API_KEY"
  2. Listar serviços de um profissional

    curl "https://api.alibit.com.br/v1/services?professionalId=PROFISSIONAL_ID" \
      -H "X-Api-Key: $ALIBIT_API_KEY"
  3. Consultar horários livres no dia

    Já considera expediente, bloqueios, outros agendamentos e a duração do serviço.

    curl "https://api.alibit.com.br/v1/appointments/availability?professionalId=PROFISSIONAL_ID&serviceId=SERVICO_ID&date=2026-10-15" \
      -H "X-Api-Key: $ALIBIT_API_KEY"
    {
      "date": "2026-10-15",
      "slots": ["2026-10-15T12:00:00.000Z", "2026-10-15T12:30:00.000Z", "…"]
    }
  4. Criar (ou reaproveitar) o cliente

    O telefone é único por empresa. Se ele já existir, a resposta é 409: busque o cliente em GET /v1/clients e use o id dele.

    curl -X POST https://api.alibit.com.br/v1/clients \
      -H "X-Api-Key: $ALIBIT_API_KEY" -H "Content-Type: application/json" \
      -d '{"name":"Maria Silva","phone":"11988887777","email":"maria@exemplo.com","birthDate":"1992-04-18"}'
  5. Criar o agendamento

    Use um dos horários retornados no passo 3. O término é calculado pela duração do serviço.

    curl -X POST https://api.alibit.com.br/v1/appointments \
      -H "X-Api-Key: $ALIBIT_API_KEY" -H "Content-Type: application/json" \
      -d '{"serviceId":"SERVICO_ID","clientId":"CLIENTE_ID","startTime":"2026-10-15T12:00:00.000Z","notes":"Primeira visita"}'

    Se o horário foi ocupado nesse meio tempo, a resposta é 409: consulte os horários livres de novo.

  6. Reagendar, confirmar ou cancelar

    # Reagendar
    curl -X PATCH https://api.alibit.com.br/v1/appointments/AGENDAMENTO_ID/reschedule \
      -H "X-Api-Key: $ALIBIT_API_KEY" -H "Content-Type: application/json" \
      -d '{"startTime":"2026-10-16T14:00:00.000Z"}'
    
    # Mudar o status: SCHEDULED, CONFIRMED, COMPLETED ou CANCELLED
    curl -X PATCH https://api.alibit.com.br/v1/appointments/AGENDAMENTO_ID/status \
      -H "X-Api-Key: $ALIBIT_API_KEY" -H "Content-Type: application/json" \
      -d '{"status":"CANCELLED"}'

Atenção: POST /v1/appointments marca na agenda do administrador dono da chave. Para listar a agenda de toda a equipe, use GET /v1/team/appointments.

Webhooks

A empresa cadastra a URL do seu sistema no painel, em Integrações → Webhooks, e escolhe os eventos. A cada mudança na agenda, enviamos um POST com JSON para essa URL.

EventoQuandoDados extras
appointment.createdAgendamento criado (painel, site de agendamento ou API)—
appointment.rescheduledMudou de horáriodata.previousStartTime
appointment.cancelledCanceladodata.previousStatus
appointment.status_changedConfirmado, concluído ou reativadodata.previousStatus
pingBotão "Testar" no painel—

Exemplo de corpo:

{
  "id": "0d8f6c2e-…",
  "event": "appointment.rescheduled",
  "createdAt": "2026-10-09T13:00:00.000Z",
  "companyId": "6f1c…",
  "data": {
    "appointment": {
      "id": "…", "status": "SCHEDULED", "source": "ADMIN",
      "startTime": "2026-10-16T14:00:00.000Z", "endTime": "2026-10-16T14:30:00.000Z",
      "originalStartTime": "2026-10-15T12:00:00.000Z", "rescheduleCount": 1, "notes": null,
      "professional": { "id": "…", "name": "Ana Souza" },
      "service": { "id": "…", "name": "Corte", "durationMinutes": 30, "price": "50.00" },
      "client": { "id": "…", "name": "Maria Silva", "phone": "11988887777", "email": "maria@exemplo.com" }
    },
    "previousStartTime": "2026-10-15T12:00:00.000Z"
  }
}

Cabeçalhos enviados

X-Webhook-EventNome do evento
X-Webhook-DeliveryId da entrega: igual em todas as tentativas do mesmo evento
X-Webhook-Signaturet=<unix>,v1=<hex>: assinatura para conferir a origem

Entrega e reenvio

  • Responda com status 2xx em até 10 segundos. Qualquer outra resposta conta como falha.
  • Em caso de falha, reenviamos depois de 1 min, 5 min, 30 min, 2 h e 12 h.
  • Um evento pode chegar mais de uma vez: use o id do evento para descartar repetidos.
  • A URL precisa ser https e responder direto: não seguimos redirecionamentos.
  • Dica: responda 200 logo e processe o evento em segundo plano.

Conferindo a assinatura

Cada URL cadastrada tem um segredo (whsec_…) mostrado no painel. A assinatura v1 é um HMAC-SHA256, com esse segredo, de "<t>.<corpo cru>". Calcule sobre o corpo exatamente como chegou, antes de converter o JSON, e recuse mensagens com mais de 5 minutos.

import { createHmac, timingSafeEqual } from 'node:crypto';

export function webhookValido(corpoCru, cabecalho, segredo) {
  const { t, v1 } = Object.fromEntries(cabecalho.split(',').map((p) => p.split('=')));
  if (Math.abs(Date.now() / 1000 - Number(t)) > 300) return false; // mais de 5 min
  const esperado = createHmac('sha256', segredo).update(`${t}.${corpoCru}`).digest('hex');
  return v1?.length === esperado.length && timingSafeEqual(Buffer.from(v1), Buffer.from(esperado));
}

// Express: leia o corpo cru nesta rota
app.post('/webhooks/alibit', express.raw({ type: 'application/json' }), (req, res) => {
  const corpo = req.body.toString('utf8');
  if (!webhookValido(corpo, req.get('X-Webhook-Signature'), process.env.ALIBIT_WEBHOOK_SECRET)) {
    return res.sendStatus(400);
  }
  res.sendStatus(200);
  processarEvento(JSON.parse(corpo)); // em segundo plano
});

Referência

Rotas da API

Todas exigem X-Api-Key e começam com https://api.alibit.com.br/v1. Campos marcados com * são obrigatórios. Para testar as rotas no navegador, veja também a referência interativa (Swagger).

Empresa

GET/companies/me

Dados da empresa da chave.

PATCH/team/company

Altera o nome da empresa. Corpo: name*.

Profissionais

GET/professionals?companyId=…

Profissionais que atendem. companyId*.

GET/professionals/{id}

Um profissional.

GET/professionals/{id}/working-hours

Expediente: lista de { weekday, startTime, endTime }.

PATCH/professionals/me

Altera o administrador dono da chave: name, phone, slotIntervalMinutes (15, 30 ou 60: intervalo entre horários livres).

PUT/professionals/me/working-hours

Substitui o expediente. Corpo: workingHours*: lista de { weekday 0–6, startTime "HH:mm", endTime "HH:mm" }.

Serviços

GET/services?professionalId=…

Serviços de um profissional. professionalId*.

GET/services/{id}

Um serviço.

POST/services

Cria um serviço do dono da chave. Corpo: name*, durationMinutes*, price* (em reais, ex.: 49.90).

PATCH/services/{id}

Altera name, durationMinutes ou price.

DELETE/services/{id}

Remove o serviço.

Clientes

GET/clients

Todos os clientes da empresa.

GET/clients/{id}

Um cliente.

GET/clients/birthdays?days=30

Aniversariantes dos próximos days dias (padrão 30).

POST/clients

Cria um cliente. Corpo: name*, phone*, email, birthDate (YYYY-MM-DD). Telefone e e-mail são únicos na empresa (409 se repetir).

PATCH/clients/{id}

Altera os mesmos campos. birthDate: null apaga a data.

DELETE/clients/{id}

Remove o cliente.

Agendamentos

GET/appointments/availability

Horários livres. Query: professionalId*, serviceId*, date* (YYYY-MM-DD), excludeAppointmentId (ao reagendar, ignora o próprio agendamento). Retorna { date, slots: [ISO…] }.

GET/appointments

Agenda do dono da chave, do mais recente ao mais antigo. Query opcional: from, to (ISO 8601), status, clientId.

GET/appointments/{id}

Um agendamento, com service e client.

POST/appointments

Cria. Corpo: serviceId*, clientId*, startTime* (ISO 8601), notes. Respeita expediente, bloqueios e conflitos (409).

PATCH/appointments/{id}/reschedule

Muda o horário. Corpo: startTime*. Guarda o horário original em originalStartTime e soma rescheduleCount.

PATCH/appointments/{id}/status

Corpo: status*: SCHEDULED, CONFIRMED, COMPLETED ou CANCELLED.

StatusSignificado
SCHEDULEDAgendado
CONFIRMEDConfirmado pelo cliente
COMPLETEDAtendimento realizado
CANCELLEDCancelado (libera o horário)

Bloqueios

Períodos em que o profissional não atende (folga, almoço, compromisso). Somem dos horários livres.

GET/blocks

Bloqueios do dono da chave. Query opcional: from, to.

POST/blocks

Corpo: startTime*, endTime* (ISO 8601), reason.

DELETE/blocks/{id}

Remove o bloqueio.

Equipe

Visão de toda a empresa, como o administrador vê no painel.

GET/team/professionals

Todos os profissionais, com papel, situação e se atendem clientes.

POST/team/professionals

Cria um profissional. Corpo: name*, email*, password* (senha provisória), phone, role (ADMIN ou PROFESSIONAL).

PATCH/team/professionals/{id}

Altera name, phone, role, active (bloquear/desbloquear) ou acceptsBookings (aparece para agendar).

GET/team/appointments

Agenda de toda a equipe. Query opcional: from, to, status, professionalId, rescheduled=true.

Suporte

Dúvidas, pedido de sandbox ou algo que não funciona como descrito aqui: escreva para contato@alibit.com.br. Mande o horário, a rota chamada e o status da resposta (nunca envie a chave completa).