> ## Documentation Index
> Fetch the complete documentation index at: https://docs.morada.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Agendamento

> Receba notificações quando uma visita ou reunião é criada ou atualizada.

## Visão Geral

O webhook de **Agendamento** é disparado pela Morada.ai sempre que uma visita ou reunião é criada ou atualizada para um deal. Inclui dados completos do agendamento, deal, contato e um resumo da conversa gerado por IA.

## Payload

```json theme={null}
{
  "deal": {
    "id": "a1b2c3d4-5678-90ab-cdef-1234567890ab",
    "status": "active",
    "stageCode": "visit_scheduled",
    "name": "Maria Oliveira - Residencial Parque Verde",
    "conversationId": "f1e2d3c4-5678-90ab-cdef-1234567890ab",
    "partnerId": "b2c3d4e5-6789-01ab-cdef-2345678901bc"
  },
  "person": {
    "id": "c3d4e5f6-7890-12ab-cdef-3456789012cd",
    "name": "Maria Oliveira",
    "email": "maria@email.com",
    "phone": "5521988888888"
  },
  "product": {
    "id": "d4e5f6a7-8901-23ab-cdef-4567890123de",
    "name": "Residencial Parque Verde"
  },
  "source": {
    "id": "e5f6a7b8-9012-34ab-cdef-5678901234ef",
    "code": "instagram",
    "name": "Instagram Ads"
  },
  "conversationReport": "A lead solicitou visita ao decorado no sábado. Tem interesse em unidades de 3 quartos no andar alto. Informou que trabalha na região e busca proximidade com metrô.",
  "appointmentDate": "17-05-2026 10:00",
  "appointment": {
    "id": "1a2b3c4d-5678-90ab-cdef-1234567890ab",
    "dealId": "a1b2c3d4-5678-90ab-cdef-1234567890ab",
    "personId": "c3d4e5f6-7890-12ab-cdef-3456789012cd",
    "propertyId": "2b3c4d5e-6789-01ab-cdef-2345678901bc",
    "scheduledAt": "2026-05-17T13:00:00.000Z",
    "status": "scheduled"
  },
  "metadata": {
    "timestamp": "2026-05-13T18:30:00.000Z",
    "eventType": "appointment"
  }
}
```

## Campos

### deal

| Campo                 | Tipo           | Descrição                             |
| --------------------- | -------------- | ------------------------------------- |
| `deal.id`             | string         | ID único do deal                      |
| `deal.status`         | string         | Status atual: `active`, `won`, `lost` |
| `deal.stageCode`      | string         | Código da etapa atual no funil        |
| `deal.name`           | string         | Nome do deal                          |
| `deal.conversationId` | string \| null | ID da conversa associada              |
| `deal.partnerId`      | string         | ID do parceiro                        |

### person

| Campo          | Tipo           | Descrição                              |
| -------------- | -------------- | -------------------------------------- |
| `person.id`    | string         | ID único do contato                    |
| `person.name`  | string \| null | Nome completo                          |
| `person.email` | string \| null | E-mail                                 |
| `person.phone` | string \| null | Telefone com DDI (ex: `5521988888888`) |

### product

<Note>
  O campo `product` só é enviado quando o deal possui um produto/empreendimento associado.
</Note>

| Campo          | Tipo   | Descrição                      |
| -------------- | ------ | ------------------------------ |
| `product.id`   | string | ID do produto/empreendimento   |
| `product.name` | string | Nome do produto/empreendimento |

### source

| Campo         | Tipo   | Descrição                                             |
| ------------- | ------ | ----------------------------------------------------- |
| `source.id`   | string | ID da origem                                          |
| `source.code` | string | Código da origem (ex: `whatsapp`, `instagram`, `web`) |
| `source.name` | string | Nome descritivo da origem                             |

### appointment

| Campo                     | Tipo           | Descrição                                                |
| ------------------------- | -------------- | -------------------------------------------------------- |
| `appointment.id`          | string         | ID único do agendamento                                  |
| `appointment.dealId`      | string         | ID do deal associado                                     |
| `appointment.personId`    | string         | ID do contato                                            |
| `appointment.propertyId`  | string \| null | ID do imóvel/empreendimento da visita                    |
| `appointment.scheduledAt` | string         | Data/hora agendada (ISO 8601, UTC)                       |
| `appointment.status`      | string         | Status: `scheduled`, `completed`, `cancelled`, `no_show` |

### Outros campos

| Campo                | Tipo           | Descrição                                                               |
| -------------------- | -------------- | ----------------------------------------------------------------------- |
| `conversationReport` | string \| null | Resumo da conversa gerado por IA                                        |
| `appointmentDate`    | string \| null | Data formatada do agendamento: `dd-MM-yyyy HH:mm` (horário de Brasília) |
| `metadata.timestamp` | string         | Data/hora do envio do webhook (ISO 8601)                                |
| `metadata.eventType` | string         | Sempre `"appointment"`                                                  |

<Tip>
  O campo `appointmentDate` é a mesma data de `appointment.scheduledAt`, mas já convertida para o horário de Brasília e formatada para exibição. Use `scheduledAt` para cálculos e `appointmentDate` para exibição.
</Tip>

## Exemplo de uso

<CodeGroup>
  ```javascript Node.js theme={null}
  app.post("/webhook/morada", (req, res) => {
    const { appointment, person, deal, appointmentDate } = req.body;

    console.log(`Agendamento ${appointment.status} para ${person.name}`);
    console.log(`Data: ${appointmentDate}`);
    console.log(`Imóvel: ${appointment.propertyId}`);

    // Criar evento no calendário, notificar corretor, etc.

    res.status(200).json({ received: true });
  });
  ```

  ```python Python theme={null}
  @app.route("/webhook/morada", methods=["POST"])
  def handle_webhook():
      data = request.json
      appointment = data["appointment"]
      person = data["person"]

      print(f"Agendamento {appointment['status']} para {person['name']}")
      print(f"Data: {data.get('appointmentDate')}")

      return jsonify({"received": True}), 200
  ```
</CodeGroup>

## Resposta esperada

Retorne um status HTTP `200` para confirmar o recebimento:

```json theme={null}
{
  "received": true
}
```

<Warning>
  Se o seu endpoint retornar um status diferente de `2xx` ou não responder dentro do timeout, a Morada.ai poderá tentar reenviar o evento. Implemente idempotência para lidar com entregas duplicadas.
</Warning>
