Marcações
A API de Marcações permite-lhe marcar reuniões para os seus contactos nos seus tipos de evento, e depois obtê-las, listá-las, atualizá-las, cancelá-las ou eliminá-las. Também responde à pergunta que surge primeiro na maioria dos fluxos de marcação — que horários estão realmente livres — e cobre a parte do calendário: listar os Google Calendars que tem ligados e importar eventos que já existem neles. Quando uma ligação ao Google Calendar está ativa, o evento de calendário correspondente é criado e mantido sincronizado automaticamente em segundo plano. Os restaurantes que utilizam Zenchef, Formitable, OpenTable ou TheFork para o seu próprio sistema de reservas também podem ser verificados e ligados aqui, para que o Agente de IA reserve mesas reais em vez de marcações internas — e as empresas de marcações que gerem a sua agenda no Trafft podem ligar-se da mesma forma.
Todos os caminhos nesta página são relativos ao URL base https://api.youraiconnector.com/v1. Cada pedido necessita da sua chave de API — consulte Autenticação para obter a lista completa de formas de a enviar. Os exemplos abaixo utilizam o cabeçalho X-API-Key, com um exemplo cURL que mostra também o formulário de consulta ?apiKey=.
Eventos vs. marcações: Um tipo de evento é uma definição de espaço reservável (o tipo de reunião, a sua duração, as suas salas). Uma marcação é uma instância reservada de um tipo de evento para um contacto específico. Reserva uma marcação referenciando o contacto e o tipo de evento.
O objeto de marcação
Cada endpoint que devolve uma marcação utiliza a mesma estrutura:
| Campo | Descrição |
|---|---|
id |
ID único do agendamento. |
contact_id |
ID do contacto com quem o agendamento foi marcado. |
event_id |
ID do tipo de evento no qual o agendamento foi marcado. null para agendamentos externos — agendamentos registados sem um tipo de evento. |
status |
Confirmed ou Canceled. |
start_time |
Início do agendamento, ISO 8601 em UTC. |
end_time |
Fim do agendamento, ISO 8601 em UTC. |
created_at |
Quando o agendamento foi criado. |
last_modified_at |
Quando o agendamento foi alterado pela última vez. |
room_name |
Sala ou recurso onde o agendamento foi marcado, quando o tipo de evento utiliza salas. |
description |
Descrição livre do agendamento. |
summary |
Resumo ou título curto. Para um agendamento externo, este é o title com o qual foi registado. |
external_reference |
O seu próprio ID para este agendamento (do seu CRM ou sistema de reservas), conforme o enviou, ou null. |
cancelation_reason |
Motivo fornecido quando o agendamento foi cancelado, se existir. |
google_calendar_event_id |
ID do evento do Google Calendar associado. Definido assim que a sincronização do calendário for concluída; null quando nenhum calendário está ligado ou enquanto a sincronização ainda está em curso. |
calendar_synced |
true assim que o agendamento estiver associado a um evento de calendário. |
imported |
true quando o agendamento foi importado de um calendário externo em vez de marcado diretamente. |
is_recurring |
true quando o agendamento faz parte de uma série recorrente. |
recurrence_frequency |
Com que frequência o agendamento se repete, quando recorrente. |
recurring_event_id |
ID da série recorrente a que este agendamento pertence. |
recurring_interval |
Intervalo entre repetições, quando recorrente. |
recurring_sequence |
Posição deste agendamento dentro da sua série recorrente. |
end_after_x_occurrences |
Número de ocorrências após as quais a série recorrente termina. |
booking_provider |
Sistema de origem de onde veio a reserva, quando marcada através de um fornecedor de reservas ligado. |
Sobre a sincronização de calendário: Logo após reservar ou alterar uma marcação, o
google_calendar_event_idpode ainda sernulle ocalendar_syncedpode serfalseporque a sincronização é executada em segundo plano um momento depois. Obtenha a marcação novamente pouco depois para ver os campos de calendário preenchidos.
Encontrar horários disponíveis
GET /appointments/available-slots
Devolve os horários que estão genuinamente livres num tipo de evento entre dois momentos. Esta é normalmente a primeira chamada num fluxo de marcação: mostre estes horários, deixe a pessoa escolher um e, em seguida, envie a hora escolhida para Marcar um compromisso.
A resposta já tem em conta o horário de funcionamento e a duração dos intervalos do próprio tipo de evento, as suas salas, as marcações que já efetuou nele e tudo o que está bloqueado nos Google Calendars ligados — por isso, um horário que aparece aqui é um horário que pode marcar.
| Parâmetro de consulta | Obrigatório | Descrição |
|---|---|---|
event_id |
Sim | O tipo de evento a verificar. Deve pertencer à sua conta. Encontre-o na aplicação abrindo o tipo de evento na página Agendamentos (separador Tipos de Evento): a janela de edição mostra o respetivo ID do tipo de evento com um botão de cópia. |
start_time |
Sim | Início da janela para a qual pretende horários, data e hora em formato ISO 8601. |
end_time |
Sim | Fim da janela, data e hora em formato ISO 8601. O dia final completo está incluído. |
Os resultados são devolvidos agrupados por dia — e, quando o tipo de evento utiliza salas, um grupo por sala por dia:
| Campo | Descrição |
|---|---|
date |
O dia que o grupo cobre, escrito DD/MM/YYYY. |
day |
Nome do dia da semana em minúsculas, por exemplo monday. |
room_name |
A sala ou recurso a que este grupo pertence, quando o tipo de evento utiliza salas. |
available_slots |
Os blocos marcáveis nesse dia, do mais cedo para o mais tarde. |
Cada entrada em available_slots tem:
| Campo | Descrição |
|---|---|
start_time |
Início do bloco como HH:mm. |
end_time |
Fim do bloco como HH:mm. |
available |
true — apenas é devolvido tempo livre. |
spots_left |
Quantas marcações ainda cabem neste bloco. Apenas presente em tipos de evento que aceitam mais do que uma marcação por intervalo. |
Os horários são locais ao tipo de evento, não UTC.
date,start_timeeend_timesão valores de relógio de parede no fuso horário do próprio tipo de evento (a sua substituição, ou o fuso horário da sua conta quando não tem nenhum). Marcar um compromisso espera um instante UTC ISO 8601, por isso converta o horário que escolheu antes de o enviar.
cURL
curl "https://api.youraiconnector.com/v1/appointments/available-slots?event_id=event_xyz789&start_time=2026-06-15T00:00:00.000Z&end_time=2026-06-19T00:00:00.000Z" \
-H "X-API-Key: YOUR_API_KEY"
JavaScript
const params = new URLSearchParams({
event_id: "event_xyz789",
start_time: "2026-06-15T00:00:00.000Z",
end_time: "2026-06-19T00:00:00.000Z",
});
const res = await fetch(
`https://api.youraiconnector.com/v1/appointments/available-slots?${params}`,
{ headers: { "X-API-Key": "YOUR_API_KEY" } }
);
const data = await res.json();
console.log(data.data);
Python
import requests
res = requests.get(
"https://api.youraiconnector.com/v1/appointments/available-slots",
headers={"X-API-Key": "YOUR_API_KEY"},
params={
"event_id": "event_xyz789",
"start_time": "2026-06-15T00:00:00.000Z",
"end_time": "2026-06-19T00:00:00.000Z",
},
)
print(res.json()["data"])
Resposta (200 OK):
{
"success": true,
"data": [
{
"date": "15/06/2026",
"day": "monday",
"room_name": "Room A",
"available_slots": [
{ "start_time": "10:00", "end_time": "10:30", "available": true },
{ "start_time": "10:30", "end_time": "11:00", "available": true }
]
},
{
"date": "16/06/2026",
"day": "tuesday",
"room_name": "Room A",
"available_slots": [
{ "start_time": "09:00", "end_time": "09:30", "available": true, "spots_left": 2 }
]
}
]
}
Um dia sem nada livre simplesmente não aparece. A falta de event_id, start_time ou end_time devolve 400; um tipo de evento que não está na sua conta devolve 404.
Reservar uma marcação
POST /appointments
Cria um agendamento para um dos seus contactos. Existem duas formas de o utilizar:
- Num dos seus tipos de evento — envie
event_id, e a reserva funciona exatamente como sempre funcionou: a disponibilidade e a capacidade são respeitadas, a hora de fim é calculada a partir da duração do intervalo do tipo de evento e o agendamento é sincronizado com o seu Google Calendar quando um estiver ligado. - Como um agendamento externo — deixe
event_idde fora e envie umtitleem vez disso. Isto regista uma reserva que foi feita noutro local (o seu próprio CRM, um horário de aulas, outra ferramenta de reservas) para que apareça na página de Agendamentos juntamente com os restantes.
Uma marcação num tipo de evento com salas deve ser feita para uma hora que Encontrar horários disponíveis ofereceria: dentro do horário da sala, fora do período de aviso prévio, dentro do limite de antecedência com que o tipo de evento pode ser marcado, na grelha de horários, não no passado e não bloqueada num calendário ligado. Qualquer outra hora é recusada com um 400 e nada é criado. O mesmo acontece com uma room_name que não corresponda a nenhuma das salas do tipo de evento (a mensagem lista os nomes válidos). Os tempos de intervalo definidos no tipo de evento (Intervalo antes e Intervalo depois no editor de tipos de evento, buffer_before e buffer_after em minutos) são mantidos livres em torno de cada marcação.
Uma marcação num tipo de evento também é verificada quanto a conflitos: se o horário já estiver ocupado, o pedido falha com um 409 e nada é criado. Uma marcação externa não tem um tipo de evento associado, por isso nada é verificado em relação à sua disponibilidade ou capacidade e nada é sincronizado com um calendário.
Tentar novamente é seguro. Se o mesmo contacto já tiver uma marcação confirmada no mesmo tipo de evento no mesmo início (na mesma sala, quando nomeia uma), por exemplo, porque o seu primeiro pedido expirou após ter sido processado, recebe essa marcação de volta com um 200 e "replayed": true em vez de uma segunda marcação ou um 409.
Um external_reference funciona como uma chave de idempotência. É único na sua conta: se um agendamento já tiver a referência que enviou, esse agendamento é devolvido com um 200 e "replayed": true e nada de novo é criado, mesmo quando a nova tentativa indica uma hora ou contacto diferente e independentemente do estado desse agendamento. Utilize-o para reservas pagas (envie o seu ID de pagamento ou de encomenda) e envie uma nova referência para uma reserva genuinamente nova.
| Campo | Obrigatório | Descrição |
|---|---|---|
contact_id |
Sim | ID do contacto para o qual efetuar a reserva. Deve pertencer à sua conta. |
start_time |
Sim | Início pretendido como data-hora ISO 8601. Uma hora enviada sem desfasamento de fuso horário é lida no fuso horário da sua conta. |
event_id |
Não | ID do tipo de evento para o qual efetuar a reserva. Deve pertencer à sua conta. Deixe em branco para registar uma reserva externa. |
title |
Apenas sem event_id |
O nome sob o qual o agendamento é apresentado na página de Agendamentos — o nome da aula, por exemplo. Até 200 caracteres. É devolvido como summary. |
end_time |
Não | Fim de uma reserva externa como data-hora ISO 8601, posterior a start_time. Não é necessário com um event_id: a hora de fim provém então da duração do intervalo do tipo de evento. |
duration_minutes |
Não | Duração de uma reserva externa, um número inteiro de minutos de 1 a 1440. Utilize este ou end_time, não ambos. Sem nenhum, uma reserva externa dura 60 minutos. |
description |
Não | Notas de formato livre para manter com o agendamento. |
room_name |
Não | Nome da sala ou recurso, quando o tipo de evento utiliza salas. Deve corresponder a uma das suas salas. Deixe em branco para reservar a primeira sala livre. |
external_reference |
Não | O seu próprio ID para esta reserva, para que possa associá-la ao registo no seu CRM ou sistema de reservas. Até 255 caracteres. É devolvido em cada leitura e nos webhooks de Agendamento Reservado, Cancelado e Reagendado. Único na sua conta: uma referência que já esteja a ser utilizada devolve esse agendamento em vez de reservar novamente (ver acima). |
Envie event_id e title em conjunto, ou nenhum dos dois, e o pedido devolve um 400 — tal como o envio de ambos end_time e duration_minutes.
cURL (utilizando o formulário de consulta ?apiKey=)
curl -X POST "https://api.youraiconnector.com/v1/appointments?apiKey=YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"contact_id": "contact_abc123",
"event_id": "event_xyz789",
"start_time": "2026-06-15T10:00:00.000Z",
"room_name": "Room A"
}'
JavaScript
const res = await fetch("https://api.youraiconnector.com/v1/appointments", {
method: "POST",
headers: {
"X-API-Key": "YOUR_API_KEY",
"Content-Type": "application/json",
},
body: JSON.stringify({
contact_id: "contact_abc123",
event_id: "event_xyz789",
start_time: "2026-06-15T10:00:00.000Z",
room_name: "Room A",
}),
});
const data = await res.json();
console.log(data.appointment_id);
Python
import requests
res = requests.post(
"https://api.youraiconnector.com/v1/appointments",
headers={
"X-API-Key": "YOUR_API_KEY",
"Content-Type": "application/json",
},
json={
"contact_id": "contact_abc123",
"event_id": "event_xyz789",
"start_time": "2026-06-15T10:00:00.000Z",
"room_name": "Room A",
},
)
print(res.json()["appointment_id"])
Resposta (201 Created):
{
"success": true,
"appointment_id": "aBcD1234eFgH5678",
"appointment": {
"id": "aBcD1234eFgH5678",
"contact_id": "contact_abc123",
"event_id": "event_xyz789",
"status": "Confirmed",
"start_time": "2026-06-15T10:00:00.000Z",
"end_time": "2026-06-15T10:30:00.000Z",
"created_at": "2026-06-10T09:00:00.000Z",
"last_modified_at": "2026-06-10T09:00:00.000Z",
"room_name": "Room A",
"google_calendar_event_id": null,
"calendar_synced": false
}
}
Registar uma reserva feita noutro local
O mesmo endpoint, sem um tipo de evento: um title e um start_time são suficientes, e duration_minutes define quanto tempo dura.
cURL
curl -X POST "https://api.youraiconnector.com/v1/appointments" \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"contact_id": "contact_abc123",
"title": "Beginner guitar class",
"start_time": "2026-06-15T10:00:00.000Z",
"duration_minutes": 90,
"external_reference": "class-slot-4812"
}'
JavaScript
const res = await fetch("https://api.youraiconnector.com/v1/appointments", {
method: "POST",
headers: {
"X-API-Key": "YOUR_API_KEY",
"Content-Type": "application/json",
},
body: JSON.stringify({
contact_id: "contact_abc123",
title: "Beginner guitar class",
start_time: "2026-06-15T10:00:00.000Z",
duration_minutes: 90,
}),
});
const data = await res.json();
console.log(data.appointment_id);
Python
import requests
res = requests.post(
"https://api.youraiconnector.com/v1/appointments",
headers={
"X-API-Key": "YOUR_API_KEY",
"Content-Type": "application/json",
},
json={
"contact_id": "contact_abc123",
"title": "Beginner guitar class",
"start_time": "2026-06-15T10:00:00.000Z",
"duration_minutes": 90,
},
)
print(res.json()["appointment_id"])
Resposta (201 Created):
{
"success": true,
"appointment_id": "eFgH5678aBcD1234",
"appointment": {
"id": "eFgH5678aBcD1234",
"contact_id": "contact_abc123",
"event_id": null,
"status": "Confirmed",
"start_time": "2026-06-15T10:00:00.000Z",
"end_time": "2026-06-15T11:30:00.000Z",
"created_at": "2026-06-10T09:00:00.000Z",
"last_modified_at": "2026-06-10T09:00:00.000Z",
"summary": "Beginner guitar class",
"google_calendar_event_id": null,
"calendar_synced": false
}
}
Os agendamentos externos são agendamentos comuns a partir daí: aparecem na página de Agendamentos e em Listar agendamentos, podem ser reagendados, cancelados ou eliminados na aplicação ou através desta API, o e-mail de notificação de agendamento é enviado como habitualmente, e o acionador de automatização Agendamento marcado e o webhook são disparados para eles como para qualquer outra reserva feita através da API. As únicas diferenças são as mencionadas acima — sem verificação de disponibilidade ou capacidade, sem sincronização de calendário, e event_id permanece null.
Obter um agendamento
GET /appointments/{appointmentId}
Devolve um único agendamento pelo seu ID, incluindo o seu estado de sincronização de calendário.
cURL
curl "https://api.youraiconnector.com/v1/appointments/aBcD1234eFgH5678" \
-H "X-API-Key: YOUR_API_KEY"
JavaScript
const res = await fetch(
"https://api.youraiconnector.com/v1/appointments/aBcD1234eFgH5678",
{ headers: { "X-API-Key": "YOUR_API_KEY" } }
);
const data = await res.json();
console.log(data.appointment);
Python
import requests
res = requests.get(
"https://api.youraiconnector.com/v1/appointments/aBcD1234eFgH5678",
headers={"X-API-Key": "YOUR_API_KEY"},
)
print(res.json()["appointment"])
Resposta (200 OK):
{
"success": true,
"appointment": {
"id": "aBcD1234eFgH5678",
"contact_id": "contact_abc123",
"event_id": "event_xyz789",
"status": "Confirmed",
"start_time": "2026-06-15T10:00:00.000Z",
"end_time": "2026-06-15T10:30:00.000Z",
"room_name": "Room A",
"google_calendar_event_id": "abc123googleevent",
"calendar_synced": true
}
}
Listar agendamentos
GET /appointments
Lista os agendamentos da sua conta, do mais recente para o mais antigo, com paginação baseada em cursor.
| Parâmetro de consulta | Obrigatório | Descrição |
|---|---|---|
contact_id |
Não | Devolve apenas agendamentos para este contacto. As listagens filtradas por contacto incluem apenas agendamentos confirmados |
date |
Não | Devolve apenas agendamentos neste dia de calendário (YYYY-MM-DD). Requer contact_id. |
status |
Não | Filtrar por Confirmed ou Canceled. Disponível apenas sem contact_id. |
limit |
Não | Tamanho da página, um número inteiro entre 1 e 100. Predefinição 50. |
cursor |
Não | O valor next_cursor de uma resposta anterior. |
Algumas regras a ter em conta:
- Sem filtros, obtém todos os agendamentos da conta, página a página.
- Por contacto — defina
contact_idpara ver os agendamentos confirmados de um contacto. Pode restringir a um único dia passando tambémdate. - Por estado — defina
status(semcontact_id) para listar apenas agendamentosConfirmedou apenasCanceledem toda a conta. - O filtro
datesemcontact_id, oustatus=Canceledjuntamente comcontact_id, devolve um400.
cURL
curl "https://api.youraiconnector.com/v1/appointments?contact_id=contact_abc123&date=2026-06-15" \
-H "X-API-Key: YOUR_API_KEY"
JavaScript
const params = new URLSearchParams({
contact_id: "contact_abc123",
date: "2026-06-15",
});
const res = await fetch(
`https://api.youraiconnector.com/v1/appointments?${params}`,
{ headers: { "X-API-Key": "YOUR_API_KEY" } }
);
const data = await res.json();
console.log(data.appointments, data.next_cursor);
Python
import requests
res = requests.get(
"https://api.youraiconnector.com/v1/appointments",
headers={"X-API-Key": "YOUR_API_KEY"},
params={"contact_id": "contact_abc123", "date": "2026-06-15"},
)
data = res.json()
print(data["appointments"], data["next_cursor"])
Resposta (200 OK):
{
"success": true,
"appointments": [
{
"id": "aBcD1234eFgH5678",
"contact_id": "contact_abc123",
"event_id": "event_xyz789",
"status": "Confirmed",
"start_time": "2026-06-15T10:00:00.000Z",
"end_time": "2026-06-15T10:30:00.000Z",
"calendar_synced": true
}
],
"next_cursor": null
}
Para navegar entre os resultados, passe o next_cursor de uma resposta como o cursor do pedido seguinte. Continue até que next_cursor seja null. Consulte Erros e Paginação para o padrão de paginação partilhado.
Atualizar um agendamento
PUT /appointments/{appointmentId}
Reagende um compromisso ou altere os seus detalhes. Envie apenas os campos que pretende alterar — é necessário pelo menos um. O início e o fim combinados devem manter-se por ordem cronológica (end_time deve ser posterior a start_time). As alterações são sincronizadas automaticamente com o evento do calendário associado.
Mover uma marcação confirmada num tipo de evento (um novo start_time ou room_name) é verificado quanto a conflitos tal como uma nova marcação: um horário que já esteja ocupado responde 409 e nada muda, e uma room_name que não corresponda a nenhuma das salas do tipo de evento responde 400. Envie apenas start_time e a marcação mantém a sua duração. O seu próprio horário de funcionamento e período de aviso prévio não são aplicados aqui, pelo que ainda pode mover uma marcação para qualquer hora livre.
| Campo | Descrição |
|---|---|
start_time |
Novo início, data-hora ISO 8601. Uma hora enviada sem desfasamento de fuso horário é lida no fuso horário do tipo de evento (ou da sua conta), da mesma forma que ao reservar. |
end_time |
Novo fim, data-hora ISO 8601, lido da mesma forma. Deve ser posterior à hora de início. |
room_name |
Novo nome de sala ou recurso. |
description |
Nova descrição, ou null para a limpar. |
summary |
Novo resumo, ou null para o limpar. |
external_reference |
Nova referência (até 255 caracteres), ou null para a limpar. Uma referência que outro agendamento já possua é recusada com um 409 e "code": "external_reference_taken". |
cURL
curl -X PUT "https://api.youraiconnector.com/v1/appointments/aBcD1234eFgH5678" \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"start_time": "2026-06-16T10:00:00.000Z",
"end_time": "2026-06-16T10:30:00.000Z"
}'
JavaScript
const res = await fetch(
"https://api.youraiconnector.com/v1/appointments/aBcD1234eFgH5678",
{
method: "PUT",
headers: {
"X-API-Key": "YOUR_API_KEY",
"Content-Type": "application/json",
},
body: JSON.stringify({
start_time: "2026-06-16T10:00:00.000Z",
end_time: "2026-06-16T10:30:00.000Z",
}),
}
);
const data = await res.json();
console.log(data.appointment);
Python
import requests
res = requests.put(
"https://api.youraiconnector.com/v1/appointments/aBcD1234eFgH5678",
headers={
"X-API-Key": "YOUR_API_KEY",
"Content-Type": "application/json",
},
json={
"start_time": "2026-06-16T10:00:00.000Z",
"end_time": "2026-06-16T10:30:00.000Z",
},
)
print(res.json()["appointment"])
Resposta (200 OK):
{
"success": true,
"appointment_id": "aBcD1234eFgH5678",
"appointment": {
"id": "aBcD1234eFgH5678",
"contact_id": "contact_abc123",
"event_id": "event_xyz789",
"status": "Confirmed",
"start_time": "2026-06-16T10:00:00.000Z",
"end_time": "2026-06-16T10:30:00.000Z",
"calendar_synced": true
}
}
Cancelar um agendamento
POST /appointments/{appointmentId}/cancel
Cancela um agendamento confirmado, registando opcionalmente um motivo. O agendamento permanece na sua conta com o estado Canceled e o evento de calendário associado é removido automaticamente em segundo plano. O cancelamento de um agendamento já cancelado devolve um 400.
| Campo | Obrigatório | Descrição |
|---|---|---|
cancellation_reason |
Não | Motivo do cancelamento, guardado no agendamento. |
cURL
curl -X POST "https://api.youraiconnector.com/v1/appointments/aBcD1234eFgH5678/cancel" \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"cancellation_reason": "Client asked to reschedule next month"
}'
JavaScript
const res = await fetch(
"https://api.youraiconnector.com/v1/appointments/aBcD1234eFgH5678/cancel",
{
method: "POST",
headers: {
"X-API-Key": "YOUR_API_KEY",
"Content-Type": "application/json",
},
body: JSON.stringify({
cancellation_reason: "Client asked to reschedule next month",
}),
}
);
const data = await res.json();
console.log(data.success);
Python
import requests
res = requests.post(
"https://api.youraiconnector.com/v1/appointments/aBcD1234eFgH5678/cancel",
headers={
"X-API-Key": "YOUR_API_KEY",
"Content-Type": "application/json",
},
json={"cancellation_reason": "Client asked to reschedule next month"},
)
print(res.json()["success"])
Resposta (200 OK):
{
"success": true,
"appointment_id": "aBcD1234eFgH5678"
}
Reenviar a confirmação da reserva
POST /appointments/{appointmentId}/resend-confirmation
Envia novamente a confirmação da reserva ao contacto, por exemplo, quando este diz que nunca a recebeu ou que foi para o spam. Duas partes, ambas enviadas a menos que desative uma delas: o e-mail de confirmação (o mesmo e-mail que o contacto recebeu quando efetuou a reserva) e, quando o agendamento está no seu Google Calendar, o convite do Google Calendar. Ambos são enviados para o endereço de e-mail do contacto.
| Campo | Obrigatório | Descrição |
|---|---|---|
email |
Não | false ignora o e-mail de confirmação. O valor predefinido é true. |
calendar_invite |
Não | false ignora o convite do Google Calendar. O valor predefinido é true. |
Cada parte retorna com o seu próprio resultado: sent, not_requested, no_contact_email, turned_off_for_event_type (o interruptor Enviar e-mail de agendamento ao contacto do tipo de evento está desligado), not_on_google_calendar, imported (agendamentos importados do seu calendário não recebem e-mail de confirmação) ou failed.
200quando pelo menos uma parte foi enviada.recipienté o endereço para onde foi enviada.409para um agendamento cancelado, um que já terminou, ou uma reserva feita através do Zenchef, Formitable, OpenTable, TheFork ou Trafft (esse sistema envia a sua própria confirmação).codeéappointment_canceled,appointment_in_pastoumanaged_by_provider.422quando nada pôde ser enviado, com o motivo emerror.
cURL
curl -X POST "https://api.youraiconnector.com/v1/appointments/aBcD1234eFgH5678/resend-confirmation" \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'
JavaScript
const res = await fetch(
"https://api.youraiconnector.com/v1/appointments/aBcD1234eFgH5678/resend-confirmation",
{
method: "POST",
headers: {
"X-API-Key": "YOUR_API_KEY",
"Content-Type": "application/json",
},
body: JSON.stringify({ calendar_invite: false }),
}
);
const data = await res.json();
console.log(data.email, data.recipient);
Python
import requests
res = requests.post(
"https://api.youraiconnector.com/v1/appointments/aBcD1234eFgH5678/resend-confirmation",
headers={
"X-API-Key": "YOUR_API_KEY",
"Content-Type": "application/json",
},
json={},
)
print(res.json())
Resposta (200 OK):
{
"success": true,
"appointment_id": "aBcD1234eFgH5678",
"email": "sent",
"calendar_invite": "sent",
"recipient": "jane@example.com"
}
Eliminar um agendamento
DELETE /appointments/{appointmentId}
Elimina permanentemente um agendamento e as suas referências. Se apenas pretende cancelar a marcação mantendo o registo, utilize cancelar em vez disso.
cURL
curl -X DELETE "https://api.youraiconnector.com/v1/appointments/aBcD1234eFgH5678" \
-H "X-API-Key: YOUR_API_KEY"
JavaScript
const res = await fetch(
"https://api.youraiconnector.com/v1/appointments/aBcD1234eFgH5678",
{ method: "DELETE", headers: { "X-API-Key": "YOUR_API_KEY" } }
);
const data = await res.json();
console.log(data.success);
Python
import requests
res = requests.delete(
"https://api.youraiconnector.com/v1/appointments/aBcD1234eFgH5678",
headers={"X-API-Key": "YOUR_API_KEY"},
)
print(res.json()["success"])
Resposta (200 OK):
{
"success": true
}
Listar os seus Google Calendars ligados
GET /appointments/google-calendars
Devolve os Google Calendars disponíveis nesta conta, diretamente do Google — útil para mostrar ao titular da conta um seletor de qual calendário importar abaixo, ou apenas para confirmar que a ligação está ativa.
Isto só funciona depois de a conta ter ligado o Google Calendar (Definições → Integrações) com, pelo menos, acesso de leitura. Se não o tiver feito, ou se o acesso concedido já não incluir o âmbito de leitura do calendário, receberá um 400 a indicar-lhe que deve ligá-lo (ou ligá-lo novamente).
cURL
curl "https://api.youraiconnector.com/v1/appointments/google-calendars" \
-H "X-API-Key: YOUR_API_KEY"
JavaScript
const res = await fetch("https://api.youraiconnector.com/v1/appointments/google-calendars", {
headers: { "X-API-Key": "YOUR_API_KEY" },
});
const data = await res.json();
console.log(data.data);
Python
import requests
res = requests.get(
"https://api.youraiconnector.com/v1/appointments/google-calendars",
headers={"X-API-Key": "YOUR_API_KEY"},
)
print(res.json()["data"])
Resposta (200 OK):
{
"success": true,
"data": [
{
"id": "primary",
"summary": "jane@example.com",
"timeZone": "America/New_York",
"accessRole": "owner",
"primary": true
},
{
"id": "abcdefg1234567890@group.calendar.google.com",
"summary": "Bookings",
"timeZone": "America/New_York",
"accessRole": "writer"
}
]
}
Cada entrada tem o formato CalendarListEntry da própria Google, pelo que os nomes dos campos seguem a camelCase da Google e não a snake_case habitual desta API — são dados da Google transmitidos tal como estão, não os nossos. Uma ligação em falta ou revogada devolve um 400 com um erro a explicar que o Google Calendar precisa de ser ligado (ou ligado novamente).
Importar eventos de um Google Calendar
POST /appointments/import-calendar-events
Extrai os eventos que já se encontram nos Google Calendar(s) ligados a uma campanha ou a um Agente de IA e transforma-os em marcações — útil na primeira vez que liga um calendário que já tem reservas. Isto pode demorar algum tempo (cada evento passa por um processo de extração para determinar a quem se destina), pelo que nunca é executado em linha: o pedido coloca em fila de espera um trabalho de fundo e devolve-lhe um job_id para consulta.
| Campo | Obrigatório | Descrição |
|---|---|---|
campaign_id |
Um destes dois | A campanha cujos calendários ligados devem ser importados. |
agent_id |
Um destes dois | O Agente de IA cujos calendários ligados devem ser importados. |
identifier |
Sim | "EMAIL" ou "PHONE_NUMBER" — que informação de contacto extrair de cada evento do calendário para corresponder ou criar o contacto a que pertence. |
Envie exatamente um de campaign_id / agent_id, nunca ambos e nunca nenhum — qualquer uma destas combinações devolve um 400. O que enviar tem de pertencer à sua conta, caso contrário receberá um 404.
cURL
curl -X POST "https://api.youraiconnector.com/v1/appointments/import-calendar-events?apiKey=YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"agent_id": "agent_abc123",
"identifier": "EMAIL"
}'
JavaScript
const res = await fetch("https://api.youraiconnector.com/v1/appointments/import-calendar-events", {
method: "POST",
headers: {
"X-API-Key": "YOUR_API_KEY",
"Content-Type": "application/json",
},
body: JSON.stringify({
agent_id: "agent_abc123",
identifier: "EMAIL",
}),
});
const data = await res.json();
console.log(data.job_id);
Python
import requests
res = requests.post(
"https://api.youraiconnector.com/v1/appointments/import-calendar-events",
headers={
"X-API-Key": "YOUR_API_KEY",
"Content-Type": "application/json",
},
json={"agent_id": "agent_abc123", "identifier": "EMAIL"},
)
print(res.json()["job_id"])
Resposta (202 Accepted):
{
"success": true,
"job_id": "jK9mQ2xR7pL4wN1t",
"status": "queued",
"campaign_id": null,
"agent_id": "agent_abc123"
}
campaign_id e agent_id devolvem o que enviou; o outro é sempre null.
Consultar o trabalho de importação
GET /appointments/import-calendar-events/{jobId}
curl "https://api.youraiconnector.com/v1/appointments/import-calendar-events/jK9mQ2xR7pL4wN1t" \
-H "X-API-Key: YOUR_API_KEY"
Resposta (200 OK):
{
"success": true,
"job_id": "jK9mQ2xR7pL4wN1t",
"status": "completed",
"message": "Imported 12 events as appointments.",
"error": null
}
status |
Significado |
|---|---|
queued |
Ainda não processado. Continue a consultar. |
processing |
A importação está em curso. Continue a consultar. |
completed |
Concluído — message contém um breve resumo legível. |
failed |
Algo correu mal — error contém o motivo. |
GET num jobId que não existe (ou que pertence a uma conta diferente) devolve 404.
Integrações de reservas externas (Zenchef / Formitable / OpenTable / TheFork / Trafft)
O Zenchef e o Formitable são sistemas de reservas de restaurantes através dos quais o seu Agente de IA pode reservar mesas reais; o Trafft é uma plataforma de agendamento para empresas de marcações, ligada uma vez por conta em vez de por restaurante. As duas plataformas de restauração possuem cada uma um widget de reserva público e não autenticado (https://api.youraiconnector.com/v1/zenchef-widget/... e https://api.youraiconnector.com/v1/formitable-widget/...) que é apresentado dentro do chat para o cliente — esses caminhos de widget são páginas HTML simples destinadas a serem abertas num navegador, não endpoints de API JSON, pelo que não estão documentados aqui. O que se segue são os endpoints de gestão de conta: verificar se um ID de restaurante pertence ao titular da conta e, em seguida, adicioná-lo, atualizá-lo ou removê-lo.
Zenchef
A ligação de um restaurante Zenchef é um processo de verificação de dois passos, para que o titular da conta prove que realmente gere o restaurante antes de este ser ligado ao bot: primeiro, verifique se o ID existe (sem revelar o nome), depois peça-lhe para escrever o nome do restaurante e verifique se corresponde.
Passo 1 — Verificar se um ID de restaurante existe
POST /appointments/zenchef-restaurants/check
| Campo | Obrigatório | Descrição |
|---|---|---|
restaurant_id |
Sim | O ID do restaurante Zenchef a verificar. |
curl -X POST "https://api.youraiconnector.com/v1/appointments/zenchef-restaurants/check?apiKey=YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "restaurant_id": "12345" }'
Resposta (200 OK):
{
"success": true,
"data": { "exists": true, "requiresNameVerification": true }
}
exists: false significa que nenhum restaurante Zenchef tem esse ID — não há mais nada a fazer. Limitado a 10 verificações por cada 5 minutos por conta; exceder este limite devolve 429.
Passo 2 — Verificar o nome do restaurante
POST /appointments/zenchef-restaurants/verify-name
| Campo | Obrigatório | Descrição |
|---|---|---|
restaurant_id |
Sim | O ID do restaurante Zenchef do passo 1. |
user_input_name |
Sim | O nome que o titular da conta escreveu — comparado com o nome real do restaurante no Zenchef (insensível a maiúsculas/minúsculas e espaços). |
curl -X POST "https://api.youraiconnector.com/v1/appointments/zenchef-restaurants/verify-name?apiKey=YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "restaurant_id": "12345", "user_input_name": "The Blue Door Bistro" }'
Resposta (200 OK):
{
"success": true,
"data": {
"verified": true,
"restaurantDetails": {
"id": "12345",
"name": "The Blue Door Bistro",
"address": "1 Rue de Rivoli, Paris",
"status": "active"
}
}
}
verified: false significa que o nome não correspondeu — restaurantDetails é omitido, peça ao titular da conta para tentar novamente. Limitado a 3 tentativas por cada 5 minutos (mais restrito do que a verificação de existência, uma vez que este é o passo de prova real). Um restaurant_id que já não é resolvido no Zenchef devolve 404.
Passo 3 — Guardar o restaurante
POST /appointments/zenchef-restaurants
| Campo | Obrigatório | Descrição |
|---|---|---|
restaurant_id |
Sim | 1–64 caracteres, letras/números/underscore/hífen. |
restaurant_name |
Sim | O nome do restaurante verificado do passo 2. |
curl -X POST "https://api.youraiconnector.com/v1/appointments/zenchef-restaurants?apiKey=YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "restaurant_id": "12345", "restaurant_name": "The Blue Door Bistro" }'
Resposta (201 Created):
{ "success": true, "data": { "restaurantId": "12345" } }
Atualizar um restaurante Zenchef guardado
PUT /appointments/zenchef-restaurants/{restaurantId}
| Campo | Obrigatório | Descrição |
|---|---|---|
restaurant_name |
Não | Novo nome de apresentação. |
is_active |
Não | Defina false para impedir que o bot efetue reservas neste restaurante sem o remover. |
curl -X PUT "https://api.youraiconnector.com/v1/appointments/zenchef-restaurants/12345" \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "is_active": false }'
Resposta (200 OK): mesma estrutura que a resposta de guardar acima.
Remover um restaurante Zenchef
DELETE /appointments/zenchef-restaurants/{restaurantId}
curl -X DELETE "https://api.youraiconnector.com/v1/appointments/zenchef-restaurants/12345" \
-H "X-API-Key: YOUR_API_KEY"
Resposta (200 OK): { "success": true, "data": { "restaurantId": "12345" } }
Um restaurantId que não esteja atualmente na conta devolve 404 ao atualizar ou eliminar.
Formitable
O Formitable não necessita da prova de nome em dois passos como o Zenchef — os seus IDs de restaurante já estão delimitados por empresa, pelo que uma chamada de verificação é suficiente. Também possui uma consulta de detalhes utilizada para colocar em cache o URL do website do restaurante durante a configuração.
Verificar um ID de restaurante
POST /appointments/formitable-restaurants/verify
| Campo | Obrigatório | Descrição |
|---|---|---|
restaurant_id |
Sim | O ID de restaurante Formitable. |
language |
Não | Etiqueta de idioma para o pedido de sondagem. O valor predefinido é "nl". |
curl -X POST "https://api.youraiconnector.com/v1/appointments/formitable-restaurants/verify?apiKey=YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "restaurant_id": "the-blue-door", "language": "en" }'
Resposta (200 OK):
{
"success": true,
"data": {
"verified": true,
"restaurantDetails": {
"restaurantId": "the-blue-door",
"productCount": 4,
"sampleProductTitle": "Dinner for two",
"language": "en"
}
}
}
Um restaurant_id que o Formitable não reconheça devolve 404. Limitado a 10 tentativas por cada 5 minutos por conta.
Obter detalhes do restaurante
GET /appointments/formitable-restaurants/{restaurantId}/details?language=en
Obtém o perfil público do restaurante a partir do Formitable, incluindo o seu website — utilizado para colocar em cache o URL do website durante a configuração do restaurante. language é um parâmetro de consulta opcional, com o valor predefinido "en".
curl "https://api.youraiconnector.com/v1/appointments/formitable-restaurants/the-blue-door/details?language=en" \
-H "X-API-Key: YOUR_API_KEY"
Resposta (200 OK):
{
"success": true,
"data": {
"uid": "the-blue-door",
"name": "The Blue Door Bistro",
"website": "https://thebluedoorbistro.com",
"email": "info@thebluedoorbistro.com",
"telephone": "+31201234567",
"streetAddress": "Prinsengracht 1",
"zipcode": "1015 AB",
"city": "Amsterdam",
"country": "Netherlands",
"countryCode": "NL",
"currency": "EUR"
}
}
Guardar o restaurante
POST /appointments/formitable-restaurants
| Campo | Obrigatório | Descrição |
|---|---|---|
restaurant_id |
Sim | 1–64 caracteres, letras/números/underscore/hífen. |
restaurant_name |
Sim | Nome a apresentar. |
language |
Sim | Etiqueta de idioma ISO, p. ex. "en" ou "en-GB". |
website_url |
Não | O website do restaurante, a partir da consulta de detalhes acima. Deve ser http(s)://. |
curl -X POST "https://api.youraiconnector.com/v1/appointments/formitable-restaurants?apiKey=YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"restaurant_id": "the-blue-door",
"restaurant_name": "The Blue Door Bistro",
"language": "en",
"website_url": "https://thebluedoorbistro.com"
}'
Resposta (201 Created): { "success": true, "data": { "restaurantId": "the-blue-door" } }
Atualizar um restaurante Formitable guardado
PUT /appointments/formitable-restaurants/{restaurantId}
| Campo | Obrigatório | Descrição |
|---|---|---|
restaurant_name |
Não | Novo nome a apresentar. |
language |
Não | Nova etiqueta de idioma ISO. |
is_active |
Não | Defina false para impedir que o bot efetue reservas neste restaurante sem o remover. |
website_url |
Não | Novo URL do website. |
curl -X PUT "https://api.youraiconnector.com/v1/appointments/formitable-restaurants/the-blue-door" \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "is_active": false }'
Resposta (200 OK): mesma estrutura que a resposta de guardar acima.
Remover um restaurante Formitable
DELETE /appointments/formitable-restaurants/{restaurantId}
curl -X DELETE "https://api.youraiconnector.com/v1/appointments/formitable-restaurants/the-blue-door" \
-H "X-API-Key: YOUR_API_KEY"
Resposta (200 OK): { "success": true, "data": { "restaurantId": "the-blue-door" } }
Um restaurantId que não esteja atualmente na conta devolve 404 ao atualizar ou eliminar.
OpenTable
Os restaurantes OpenTable são acedidos através das credenciais de parceiro OpenTable da plataforma, e o OpenTable apenas permite que essas credenciais vejam os restaurantes que ligaram a listagem da plataforma dentro do Marketplace de Integrações do OpenTable. Portanto, tal como no Formitable, uma chamada de verificação é suficiente: um ID de Restaurante alcançável (o “RID” numérico) prova tanto que o restaurante existe como que ligou a integração. Até que a listagem de parceiro OpenTable seja ativada na plataforma, a chamada de verificação responde 503.
Verificar um restaurante OpenTable
POST /appointments/opentable-restaurants/verify
| Campo | Obrigatório | Descrição |
|---|---|---|
restaurant_id |
Sim | O ID de Restaurante (RID) do OpenTable, um número como 1038007. |
curl -X POST "https://api.youraiconnector.com/v1/appointments/opentable-restaurants/verify?apiKey=YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "restaurant_id": "1038007" }'
Resposta (200 OK):
{
"success": true,
"data": {
"verified": true,
"restaurantDetails": {
"restaurantId": "1038007",
"diningAreaCount": 2,
"diningAreaNames": ["Main Room", "Garden"],
"tableTypes": ["default", "outdoor", "bar"]
}
}
}
verified: false significa que nenhum restaurante OpenTable tem esse ID. Um 403 significa que o restaurante existe, mas ainda não ligou a integração da plataforma dentro do OpenTable. Limitado a 10 tentativas por cada 5 minutos por conta.
Adicionar um restaurante OpenTable
POST /appointments/opentable-restaurants
| Campo | Obrigatório | Descrição |
|---|---|---|
restaurant_id |
Sim | O ID de Restaurante verificado. |
restaurant_name |
Sim | Nome de exibição (uma etiqueta; também o que a IA chama ao restaurante). |
website_url |
Não | Um URL http(s) mostrado aos convidados quando a IA os reencaminha para o restaurante. |
curl -X POST "https://api.youraiconnector.com/v1/appointments/opentable-restaurants?apiKey=YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "restaurant_id": "1038007", "restaurant_name": "The Blue Door", "website_url": "https://thebluedoor.example" }'
Resposta (201 Created): { "success": true, "data": { "restaurantId": "1038007" } }
Atualizar um restaurante OpenTable guardado
PUT /appointments/opentable-restaurants/{restaurantId}
Envie qualquer um de restaurant_name, is_active (pausa com false) ou website_url (uma string vazia limpa o campo); os campos omitidos permanecem inalterados.
curl -X PUT "https://api.youraiconnector.com/v1/appointments/opentable-restaurants/1038007" \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "is_active": false }'
Resposta (200 OK): { "success": true, "data": { "restaurantId": "1038007" } }
Remover um restaurante OpenTable
DELETE /appointments/opentable-restaurants/{restaurantId}
curl -X DELETE "https://api.youraiconnector.com/v1/appointments/opentable-restaurants/1038007" \
-H "X-API-Key: YOUR_API_KEY"
Resposta (200 OK): { "success": true, "data": { "restaurantId": "1038007" } }
Um restaurantId que não esteja atualmente na conta devolve 404 na atualização.
TheFork
Os restaurantes do TheFork são acedidos através das credenciais de parceiro TheFork da plataforma, e o TheFork apenas permite que essas credenciais vejam restaurantes que tenham o parceiro da plataforma ativado na sua conta TheFork. Portanto, tal como no Formitable e no OpenTable, uma chamada de verificação é suficiente: um ID de Restaurante alcançável prova tanto que o restaurante existe como que o parceiro está ativado nele. O ID é o UUID que o TheFork atribui ao restaurante no TheFork Manager, enviado como uma string. Até que o TheFork tenha aprovado a plataforma como parceiro e emitido as credenciais, a chamada de verificação responde 503 — consulte TheFork para saber o que isso significa atualmente.
Verificar um restaurante TheFork
POST /appointments/thefork-restaurants/verify
| Campo | Obrigatório | Descrição |
|---|---|---|
restaurant_id |
Sim | O ID de Restaurante do TheFork, um UUID como 9f2a1c34-5b6d-4e7f-8a90-1b2c3d4e5f60. |
curl -X POST "https://api.youraiconnector.com/v1/appointments/thefork-restaurants/verify?apiKey=YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "restaurant_id": "9f2a1c34-5b6d-4e7f-8a90-1b2c3d4e5f60" }'
Resposta (200 OK):
{
"success": true,
"data": {
"verified": true,
"restaurantDetails": {
"restaurantId": "9f2a1c34-5b6d-4e7f-8a90-1b2c3d4e5f60",
"partySizes": [1, 2, 3, 4, 5, 6, 7, 8]
}
}
}
partySizes são os tamanhos de grupo que o restaurante aceita online nos próximos 30 dias. Um 404 ou 403 significa que o TheFork não nos forneceu um restaurante com esse ID — ou o ID está incorreto, ou o parceiro da plataforma ainda não está ativado nesse restaurante; um 400 significa que o ID não é um UUID. Limitado a 10 tentativas por cada 5 minutos por conta.
Adicionar um restaurante TheFork
POST /appointments/thefork-restaurants
| Campo | Obrigatório | Descrição |
|---|---|---|
restaurant_id |
Sim | O ID de Restaurante verificado (UUID). |
restaurant_name |
Sim | Nome de exibição (uma etiqueta; também o nome pelo qual a IA chama o restaurante). |
website_url |
Não | Um URL http(s) mostrado aos convidados quando a IA os encaminha para o restaurante. |
curl -X POST "https://api.youraiconnector.com/v1/appointments/thefork-restaurants?apiKey=YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "restaurant_id": "9f2a1c34-5b6d-4e7f-8a90-1b2c3d4e5f60", "restaurant_name": "The Blue Door", "website_url": "https://thebluedoor.example" }'
Resposta (201 Created): { "success": true, "data": { "restaurantId": "9f2a1c34-5b6d-4e7f-8a90-1b2c3d4e5f60" } }
Atualizar um restaurante TheFork guardado
PUT /appointments/thefork-restaurants/{restaurantId}
Envie qualquer um de restaurant_name, is_active (pausa com false) ou website_url (uma string vazia limpa o campo); os campos omitidos permanecem inalterados.
curl -X PUT "https://api.youraiconnector.com/v1/appointments/thefork-restaurants/9f2a1c34-5b6d-4e7f-8a90-1b2c3d4e5f60" \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "is_active": false }'
Resposta (200 OK): { "success": true, "data": { "restaurantId": "9f2a1c34-5b6d-4e7f-8a90-1b2c3d4e5f60" } }
Remover um restaurante TheFork
DELETE /appointments/thefork-restaurants/{restaurantId}
curl -X DELETE "https://api.youraiconnector.com/v1/appointments/thefork-restaurants/9f2a1c34-5b6d-4e7f-8a90-1b2c3d4e5f60" \
-H "X-API-Key: YOUR_API_KEY"
Resposta (200 OK): { "success": true, "data": { "restaurantId": "9f2a1c34-5b6d-4e7f-8a90-1b2c3d4e5f60" } }
Um restaurantId que não esteja atualmente na conta devolve 404 ao atualizar ou eliminar.
Trafft
O Trafft é ligado uma vez para toda a conta, não por localização: um endereço de empresa mais as credenciais da API do painel de administração do Trafft (Features & Integrations → API & Connectors, parte do plano Business do Trafft). A chamada de ligação verifica essas credenciais junto do Trafft antes de guardar qualquer coisa, pelo que um endereço errado, credenciais erradas ou um plano sem acesso à API falharão aqui em vez de durante uma conversa com o cliente. O segredo do cliente é guardado encriptado e nunca é devolvido por nenhum endpoint.
Todas as três chamadas de escrita (POST, PUT, DELETE) requerem a permissão de edição de Integrações; o estado GET necessita de visualização de Integrações.
Ligar Trafft
POST /appointments/trafft/connect
| Campo | Obrigatório | Descrição |
|---|---|---|
subdomain |
Sim | O endereço da empresa — a parte antes de .admin.trafft.com no URL em que inicia sessão, por exemplo acme. Um endereço completo é aceite e reduzido ao mesmo valor. |
client_id |
Sim | ID de cliente da página API & Connectors do Trafft. |
client_secret |
Sim | Segredo do cliente da mesma página. Guardado encriptado, nunca devolvido. |
company_name |
Não | Uma etiqueta para a sua própria lista. |
curl -X POST "https://api.youraiconnector.com/v1/appointments/trafft/connect?apiKey=YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"subdomain": "acme",
"client_id": "YOUR_TRAFFT_CLIENT_ID",
"client_secret": "YOUR_TRAFFT_CLIENT_SECRET",
"company_name": "Acme Salon"
}'
Resposta (200 OK):
{
"success": true,
"data": {
"subdomain": "acme",
"service_count": 12,
"employee_count": 4,
"location_count": 2
}
}
As contagens são devolvidas pelo Trafft durante a verificação — são a forma mais rápida de confirmar que as credenciais apontam para a conta que pretendia.
Obter o estado da ligação
GET /appointments/trafft
curl "https://api.youraiconnector.com/v1/appointments/trafft" \
-H "X-API-Key: YOUR_API_KEY"
Resposta (200 OK):
{
"success": true,
"data": {
"connected": true,
"subdomain": "acme",
"hostname": "acme.admin.trafft.com",
"client_id": "YOUR_TRAFFT_CLIENT_ID",
"company_name": "Acme Salon",
"is_active": true,
"service_count": 12,
"employee_count": 4,
"location_count": 2
}
}
connected: false significa que ainda não foi configurado nada. O segredo do cliente nunca é incluído nesta resposta.
Atualizar a ligação
PUT /appointments/trafft
| Campo | Obrigatório | Descrição |
|---|---|---|
is_active |
Não | Defina false para pausar — a IA deixa de efetuar marcações no Trafft, mas a ligação permanece. true retoma-a. |
company_name |
Não | Nova etiqueta. |
curl -X PUT "https://api.youraiconnector.com/v1/appointments/trafft" \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "is_active": false }'
Resposta (200 OK): o mesmo objeto de ligação que o GET acima.
Desligar Trafft
DELETE /appointments/trafft
curl -X DELETE "https://api.youraiconnector.com/v1/appointments/trafft" \
-H "X-API-Key: YOUR_API_KEY"
Resposta (200 OK): { "success": true }
Desligar remove apenas as credenciais armazenadas. As marcações já existentes no Trafft permanecem inalteradas.
Formato de erro em todos os endpoints Zenchef/Formitable/OpenTable/TheFork: ao contrário do resto desta página, os erros aqui apresentam o estado duas vezes — uma como estado HTTP e outra como
error_codeno corpo — por exemplo{ "success": false, "error": "Restaurant not found", "error_code": 404 }. Trate-o da mesma forma que qualquer outro erro: verifiquesuccess, leiaerrorpara obter a mensagem.
Erros da API de marcações
Os endpoints de marcações devolvem o envelope de erro padrão:
{
"success": false,
"error": "Appointment not found"
}
| Estado | Quando ocorre num endpoint de agendamento |
|---|---|
400 |
Um campo obrigatório está em falta ou é inválido — por exemplo, um start_time incorreto, um end_time não posterior a start_time, uma combinação de filtros inválida, sem campos para atualizar, ou um agendamento já cancelado. Ao reservar: nem event_id nem title enviados, ambos enviados em conjunto, ambos end_time e duration_minutes enviados, um title com mais de 200 caracteres, ou um duration_minutes fora de 1–1440. |
404 |
O agendamento, contacto ou tipo de evento não foi encontrado. |
409 |
O intervalo de tempo solicitado já está ocupado (conflito de reserva), ou numa atualização, a external_reference já está a ser utilizada por outro agendamento. |
Os códigos partilhados que qualquer endpoint pode devolver — 401, 403 (o seu plano não inclui acesso à API), 429 (limite de taxa) e 500 — estão listados com orientações de repetição em Erros e Paginação.
Próximos passos
- Contactos — crie e procure os contactos para os quais efetua reservas.
- Mensagens e Conversas — envie uma confirmação ou um lembrete a um contacto.
- Webhooks — receba notificações quando os agendamentos forem alterados.