> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://api-docs.nilo.services/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://api-docs.nilo.services/_mcp/server.

# Agendamento

> Marcar, cancelar e consultar agendamentos entre paciente e profissional, no padrão FHIR Appointment.

Um **agendamento** é o compromisso marcado entre um paciente e um profissional: quando, com
quem, e se é online ou presencial. No Nilo Care ele aparece na ficha do paciente, nas seções
**Agendamentos liberados** e **Agendamentos marcados** — e, nas implantações com a tela nova,
também em **Passados**.

No FHIR o recurso é o [`Appointment`](https://hl7.org/fhir/R4/appointment.html), e esta
integração o usa nas duas pontas.

> **Warning**
>
> **Dois campos do FHIR se cruzam aqui, e é fácil errar.** O **título** do agendamento vai em
> `description`, e as **observações** vão em `comment` — não o contrário. Trocá-los grava o texto
> livre no campo de título da plataforma.
>
> Nenhum dos dois é exibido nas telas de agendamento hoje: o que a equipe vê na lista é o nome do
> profissional e a especialidade. Mas eles ficam gravados, e é pelo nome certo que outros sistemas
> os leem.

## Campos

A coluna **No Nilo Care** traz o rótulo com que o dado aparece para a equipe; são rótulos, não
caminhos de navegação.

| Campo                                   | Obrigatório        | O que significa                                                                     | No Nilo Care                             |
| --------------------------------------- | ------------------ | ----------------------------------------------------------------------------------- | ---------------------------------------- |
| `resourceType`                          | **sim**            | Constante `Appointment`                                                             | —                                        |
| `identifier`                            | **sim**            | Suas chaves do agendamento. É por elas que a API decide entre criar e atualizar     | —                                        |
| `status`                                | **sim**            | A situação. Oito valores aceitos, quatro situações — veja abaixo                    | a seção onde o agendamento aparece       |
| `start`                                 | **sim** na escrita | Início previsto                                                                     | a data e a hora na linha do agendamento  |
| `end`                                   | **sim** na escrita | Fim previsto. Tem de ser maior que o `start`                                        | a hora final, na mesma linha             |
| `participant`                           | **sim**            | Exatamente um paciente e um profissional                                            | **Selecione o profissional responsável** |
| `description`                           | não                | O **título** do agendamento                                                         | — (não é exibido)                        |
| `comment`                               | não                | As observações, em texto livre                                                      | — (não é exibido)                        |
| `appointmentType`                       | não                | Modalidade: online ou presencial                                                    | **Consulta será**                        |
| `extension` `appointment-allowConflict` | não                | Dispensa a conferência da agenda do profissional ao gravar. **Ausente vale `true`** | —                                        |
| `created`                               | não                | Só resposta: quando o agendamento foi criado                                        | —                                        |
| `contained[]`                           | não                | Só resposta: a sala de vídeo, quando há                                             | —                                        |
| `id` · `meta`                           | não                | Só resposta: identificador Nilo FHIR e metadados da gravação                        | —                                        |

### Sobreposição de horário

A plataforma sabe conferir a agenda do profissional antes de gravar: o horário não pode colidir
com outro compromisso, e precisa estar dentro dos horários em que ele atende. **Pela integração
essa conferência não roda por padrão.** Um `Appointment` que chega sem a extensão
`appointment-allowConflict` é gravado como se ela viesse com `valueBoolean: true` — o horário que
você enviou é tratado como decisão já tomada do seu lado.

Mandar a extensão com `true` explicita o que já é o padrão:

### Request

POST [https://landing-zone-api.nilo.services/fhir/resources/Appointment](https://landing-zone-api.nilo.services/fhir/resources/Appointment)

**`Agendar permitindo sobreposição`**

```curl Agendar permitindo sobreposição
curl -X POST https://landing-zone-api.nilo.services/fhir/resources/Appointment \
     -H "x-api-key: <apiKey>" \
     -H "Content-Type: application/json" \
     -d '{
  "resourceType": "Appointment",
  "identifier": [
    {
      "system": "https://www.acmesaude.com.br/integracao/agendamento/",
      "value": "AG-3003",
      "use": "usual"
    }
  ],
  "status": "booked",
  "participant": [
    {
      "actor": {
        "identifier": {
          "system": "https://www.acmesaude.com.br/integracao/paciente/",
          "value": "507823709",
          "use": "usual"
        },
        "type": "Patient"
      },
      "status": "accepted"
    },
    {
      "actor": {
        "identifier": {
          "system": "https://www.acmesaude.com.br/integracao/profissional/",
          "value": "5032932",
          "use": "usual"
        },
        "type": "Practitioner"
      },
      "status": "accepted"
    }
  ],
  "start": "2026-06-16T11:00:00+00:00",
  "end": "2026-06-16T11:20:00+00:00",
  "description": "Encaixe — cardiologia",
  "extension": [
    {
      "url": "https://landing-zone-api.nilo.services/fhir/resources/StructureDefinition/appointment-allowConflict",
      "valueBoolean": true
    }
  ]
}'
```

**`Agendar permitindo sobreposição`**

```python Agendar permitindo sobreposição
import requests

url = "https://landing-zone-api.nilo.services/fhir/resources/Appointment"

payload = {
    "resourceType": "Appointment",
    "identifier": [
        {
            "system": "https://www.acmesaude.com.br/integracao/agendamento/",
            "value": "AG-3003",
            "use": "usual"
        }
    ],
    "status": "booked",
    "participant": [
        {
            "actor": {
                "identifier": {
                    "system": "https://www.acmesaude.com.br/integracao/paciente/",
                    "value": "507823709",
                    "use": "usual"
                },
                "type": "Patient"
            },
            "status": "accepted"
        },
        {
            "actor": {
                "identifier": {
                    "system": "https://www.acmesaude.com.br/integracao/profissional/",
                    "value": "5032932",
                    "use": "usual"
                },
                "type": "Practitioner"
            },
            "status": "accepted"
        }
    ],
    "start": "2026-06-16T11:00:00+00:00",
    "end": "2026-06-16T11:20:00+00:00",
    "description": "Encaixe — cardiologia",
    "extension": [
        {
            "url": "https://landing-zone-api.nilo.services/fhir/resources/StructureDefinition/appointment-allowConflict",
            "valueBoolean": True
        }
    ]
}
headers = {
    "x-api-key": "<apiKey>",
    "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.json())
```

**`Agendar permitindo sobreposição`**

```javascript Agendar permitindo sobreposição
const url = 'https://landing-zone-api.nilo.services/fhir/resources/Appointment';
const options = {
  method: 'POST',
  headers: {'x-api-key': '<apiKey>', 'Content-Type': 'application/json'},
  body: '{"resourceType":"Appointment","identifier":[{"system":"https://www.acmesaude.com.br/integracao/agendamento/","value":"AG-3003","use":"usual"}],"status":"booked","participant":[{"actor":{"identifier":{"system":"https://www.acmesaude.com.br/integracao/paciente/","value":"507823709","use":"usual"},"type":"Patient"},"status":"accepted"},{"actor":{"identifier":{"system":"https://www.acmesaude.com.br/integracao/profissional/","value":"5032932","use":"usual"},"type":"Practitioner"},"status":"accepted"}],"start":"2026-06-16T11:00:00+00:00","end":"2026-06-16T11:20:00+00:00","description":"Encaixe — cardiologia","extension":[{"url":"https://landing-zone-api.nilo.services/fhir/resources/StructureDefinition/appointment-allowConflict","valueBoolean":true}]}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

**`Agendar permitindo sobreposição`**

```go Agendar permitindo sobreposição
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://landing-zone-api.nilo.services/fhir/resources/Appointment"

	payload := strings.NewReader("{\n  \"resourceType\": \"Appointment\",\n  \"identifier\": [\n    {\n      \"system\": \"https://www.acmesaude.com.br/integracao/agendamento/\",\n      \"value\": \"AG-3003\",\n      \"use\": \"usual\"\n    }\n  ],\n  \"status\": \"booked\",\n  \"participant\": [\n    {\n      \"actor\": {\n        \"identifier\": {\n          \"system\": \"https://www.acmesaude.com.br/integracao/paciente/\",\n          \"value\": \"507823709\",\n          \"use\": \"usual\"\n        },\n        \"type\": \"Patient\"\n      },\n      \"status\": \"accepted\"\n    },\n    {\n      \"actor\": {\n        \"identifier\": {\n          \"system\": \"https://www.acmesaude.com.br/integracao/profissional/\",\n          \"value\": \"5032932\",\n          \"use\": \"usual\"\n        },\n        \"type\": \"Practitioner\"\n      },\n      \"status\": \"accepted\"\n    }\n  ],\n  \"start\": \"2026-06-16T11:00:00+00:00\",\n  \"end\": \"2026-06-16T11:20:00+00:00\",\n  \"description\": \"Encaixe — cardiologia\",\n  \"extension\": [\n    {\n      \"url\": \"https://landing-zone-api.nilo.services/fhir/resources/StructureDefinition/appointment-allowConflict\",\n      \"valueBoolean\": true\n    }\n  ]\n}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("x-api-key", "<apiKey>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

**`Agendar permitindo sobreposição`**

```ruby Agendar permitindo sobreposição
require 'uri'
require 'net/http'

url = URI("https://landing-zone-api.nilo.services/fhir/resources/Appointment")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["x-api-key"] = '<apiKey>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"resourceType\": \"Appointment\",\n  \"identifier\": [\n    {\n      \"system\": \"https://www.acmesaude.com.br/integracao/agendamento/\",\n      \"value\": \"AG-3003\",\n      \"use\": \"usual\"\n    }\n  ],\n  \"status\": \"booked\",\n  \"participant\": [\n    {\n      \"actor\": {\n        \"identifier\": {\n          \"system\": \"https://www.acmesaude.com.br/integracao/paciente/\",\n          \"value\": \"507823709\",\n          \"use\": \"usual\"\n        },\n        \"type\": \"Patient\"\n      },\n      \"status\": \"accepted\"\n    },\n    {\n      \"actor\": {\n        \"identifier\": {\n          \"system\": \"https://www.acmesaude.com.br/integracao/profissional/\",\n          \"value\": \"5032932\",\n          \"use\": \"usual\"\n        },\n        \"type\": \"Practitioner\"\n      },\n      \"status\": \"accepted\"\n    }\n  ],\n  \"start\": \"2026-06-16T11:00:00+00:00\",\n  \"end\": \"2026-06-16T11:20:00+00:00\",\n  \"description\": \"Encaixe — cardiologia\",\n  \"extension\": [\n    {\n      \"url\": \"https://landing-zone-api.nilo.services/fhir/resources/StructureDefinition/appointment-allowConflict\",\n      \"valueBoolean\": true\n    }\n  ]\n}"

response = http.request(request)
puts response.read_body
```

**`Agendar permitindo sobreposição`**

```java Agendar permitindo sobreposição
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://landing-zone-api.nilo.services/fhir/resources/Appointment")
  .header("x-api-key", "<apiKey>")
  .header("Content-Type", "application/json")
  .body("{\n  \"resourceType\": \"Appointment\",\n  \"identifier\": [\n    {\n      \"system\": \"https://www.acmesaude.com.br/integracao/agendamento/\",\n      \"value\": \"AG-3003\",\n      \"use\": \"usual\"\n    }\n  ],\n  \"status\": \"booked\",\n  \"participant\": [\n    {\n      \"actor\": {\n        \"identifier\": {\n          \"system\": \"https://www.acmesaude.com.br/integracao/paciente/\",\n          \"value\": \"507823709\",\n          \"use\": \"usual\"\n        },\n        \"type\": \"Patient\"\n      },\n      \"status\": \"accepted\"\n    },\n    {\n      \"actor\": {\n        \"identifier\": {\n          \"system\": \"https://www.acmesaude.com.br/integracao/profissional/\",\n          \"value\": \"5032932\",\n          \"use\": \"usual\"\n        },\n        \"type\": \"Practitioner\"\n      },\n      \"status\": \"accepted\"\n    }\n  ],\n  \"start\": \"2026-06-16T11:00:00+00:00\",\n  \"end\": \"2026-06-16T11:20:00+00:00\",\n  \"description\": \"Encaixe — cardiologia\",\n  \"extension\": [\n    {\n      \"url\": \"https://landing-zone-api.nilo.services/fhir/resources/StructureDefinition/appointment-allowConflict\",\n      \"valueBoolean\": true\n    }\n  ]\n}")
  .asString();
```

**`Agendar permitindo sobreposição`**

```php Agendar permitindo sobreposição
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://landing-zone-api.nilo.services/fhir/resources/Appointment', [
  'body' => '{
  "resourceType": "Appointment",
  "identifier": [
    {
      "system": "https://www.acmesaude.com.br/integracao/agendamento/",
      "value": "AG-3003",
      "use": "usual"
    }
  ],
  "status": "booked",
  "participant": [
    {
      "actor": {
        "identifier": {
          "system": "https://www.acmesaude.com.br/integracao/paciente/",
          "value": "507823709",
          "use": "usual"
        },
        "type": "Patient"
      },
      "status": "accepted"
    },
    {
      "actor": {
        "identifier": {
          "system": "https://www.acmesaude.com.br/integracao/profissional/",
          "value": "5032932",
          "use": "usual"
        },
        "type": "Practitioner"
      },
      "status": "accepted"
    }
  ],
  "start": "2026-06-16T11:00:00+00:00",
  "end": "2026-06-16T11:20:00+00:00",
  "description": "Encaixe — cardiologia",
  "extension": [
    {
      "url": "https://landing-zone-api.nilo.services/fhir/resources/StructureDefinition/appointment-allowConflict",
      "valueBoolean": true
    }
  ]
}',
  'headers' => [
    'Content-Type' => 'application/json',
    'x-api-key' => '<apiKey>',
  ],
]);

echo $response->getBody();
```

**`Agendar permitindo sobreposição`**

```csharp Agendar permitindo sobreposição
using RestSharp;

var client = new RestClient("https://landing-zone-api.nilo.services/fhir/resources/Appointment");
var request = new RestRequest(Method.POST);
request.AddHeader("x-api-key", "<apiKey>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"resourceType\": \"Appointment\",\n  \"identifier\": [\n    {\n      \"system\": \"https://www.acmesaude.com.br/integracao/agendamento/\",\n      \"value\": \"AG-3003\",\n      \"use\": \"usual\"\n    }\n  ],\n  \"status\": \"booked\",\n  \"participant\": [\n    {\n      \"actor\": {\n        \"identifier\": {\n          \"system\": \"https://www.acmesaude.com.br/integracao/paciente/\",\n          \"value\": \"507823709\",\n          \"use\": \"usual\"\n        },\n        \"type\": \"Patient\"\n      },\n      \"status\": \"accepted\"\n    },\n    {\n      \"actor\": {\n        \"identifier\": {\n          \"system\": \"https://www.acmesaude.com.br/integracao/profissional/\",\n          \"value\": \"5032932\",\n          \"use\": \"usual\"\n        },\n        \"type\": \"Practitioner\"\n      },\n      \"status\": \"accepted\"\n    }\n  ],\n  \"start\": \"2026-06-16T11:00:00+00:00\",\n  \"end\": \"2026-06-16T11:20:00+00:00\",\n  \"description\": \"Encaixe — cardiologia\",\n  \"extension\": [\n    {\n      \"url\": \"https://landing-zone-api.nilo.services/fhir/resources/StructureDefinition/appointment-allowConflict\",\n      \"valueBoolean\": true\n    }\n  ]\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

**`Agendar permitindo sobreposição`**

```swift Agendar permitindo sobreposição
import Foundation

let headers = [
  "x-api-key": "<apiKey>",
  "Content-Type": "application/json"
]
let parameters = [
  "resourceType": "Appointment",
  "identifier": [
    [
      "system": "https://www.acmesaude.com.br/integracao/agendamento/",
      "value": "AG-3003",
      "use": "usual"
    ]
  ],
  "status": "booked",
  "participant": [
    [
      "actor": [
        "identifier": [
          "system": "https://www.acmesaude.com.br/integracao/paciente/",
          "value": "507823709",
          "use": "usual"
        ],
        "type": "Patient"
      ],
      "status": "accepted"
    ],
    [
      "actor": [
        "identifier": [
          "system": "https://www.acmesaude.com.br/integracao/profissional/",
          "value": "5032932",
          "use": "usual"
        ],
        "type": "Practitioner"
      ],
      "status": "accepted"
    ]
  ],
  "start": "2026-06-16T11:00:00+00:00",
  "end": "2026-06-16T11:20:00+00:00",
  "description": "Encaixe — cardiologia",
  "extension": [
    [
      "url": "https://landing-zone-api.nilo.services/fhir/resources/StructureDefinition/appointment-allowConflict",
      "valueBoolean": true
    ]
  ]
] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://landing-zone-api.nilo.services/fhir/resources/Appointment")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```

Para pedir a conferência num agendamento, envie a extensão com `valueBoolean: false` — com a
ressalva do terceiro aviso abaixo.

> **Warning**
>
> **`true` dispensa mais do que a colisão de horário.** Com ele, a plataforma para de conferir a
> agenda daquele agendamento por inteiro — e passam também:
>
> * horários **fora da grade de atendimento** do profissional, que a conferência recusa ainda que
>   não colidam com nada;
> * um segundo agendamento do **mesmo paciente no mesmo horário**, e um segundo agendamento do
>   **mesmo profissional no mesmo horário**, que a conferência barra como duplicidade.
>
> Como `true` é o padrão, é disso que você abre mão em cada agendamento enviado, e são as três
> juntas — não há como dispensar uma e manter as outras.

> **Warning**
>
> **Um agendamento gravado com `true` deixa de bloquear os outros.** Ele não entra na conferência
> de horário dos agendamentos seguintes: um agendamento comum, marcado depois no mesmo horário, é
> aceito como se o primeiro não existisse — e é aceito **sem** extensão nenhuma.
>
> O efeito não termina naquela chamada, e `true` é o padrão: cada agendamento que você envia
> degrada a conferência de agenda para todo mundo que marca depois, inclusive pela tela.

> **Warning**
>
> **`false` não é o contrário de `true` aqui.** Ele não recusa a sobreposição: deixa a decisão para
> a configuração de sobreposição do seu care provider. Se essa configuração está habilitada, a
> sobreposição continua permitida e a resposta devolve `true` — não há como recusá-la agendamento
> por agendamento. Para desabilitá-la, fale com o time de suporte.

> **Warning**
>
> **Na atualização, omitir a extensão não preserva o `false` anterior.** O padrão vale em toda
> escrita, não só na criação: um update que chega sem a extensão sobrescreve com `true` o `false`
> gravado antes. Para manter o `false`, reenvie-o em cada update daquele agendamento.

> **Note**
>
> Uma extensão com a **URL errada**, ou cujo valor não venha em `valueBoolean`, é ignorada — e
> ignorada vale `true`. Um `false` escrito errado não recusa nada, e não há erro avisando: confira
> a URL antes de concluir que a conferência está valendo.

> **Note**
>
> A extensão vem em **toda** leitura de `Appointment`, com `true` ou com `false` — não só nos
> agendamentos que a usaram na escrita. Um `false` na resposta significa "a conferência de agenda
> valeu para este agendamento", não "você mandou `false`".

A URL completa da extensão está em [Extensões](/guia/conceitos/extensoes) — aqui ela aparece só
pelo nome final.

### `status`: oito valores entram, seis saem

A escrita aceita oito valores do FHIR e os reduz a quatro situações da plataforma. A leitura
devolve a situação, não o que você mandou:

| Você envia                                                   | A plataforma registra   | A leitura devolve |
| ------------------------------------------------------------ | ----------------------- | ----------------- |
| `booked` · `proposed` · `pending` · `arrived` · `checked-in` | Agendado                | `booked`          |
| `cancelled`                                                  | Cancelado               | `cancelled`       |
| `noshow`                                                     | Paciente não compareceu | `noshow`          |
| `fulfilled`                                                  | Realizado               | `fulfilled`       |

A leitura, por sua vez, traduz **nove** situações da plataforma em seis códigos:

| Situação no Nilo Care             | `status`    |
| --------------------------------- | ----------- |
| Agendado                          | `booked`    |
| Reagendado                        | `booked`    |
| Recorrente                        | `booked`    |
| Liberado                          | `proposed`  |
| Cancelado                         | `cancelled` |
| Não compareceu                    | `noshow`    |
| Não compareceu, com justificativa | `noshow`    |
| Bloqueado / indisponível          | `waitlist`  |
| Realizado                         | `fulfilled` |

> **Note**
>
> Um agendamento **reagendado** e um **recorrente** voltam como `booked`, iguais a um agendamento
> comum. Não há campo que diga que ele foi remarcado, nem que ele faz parte de uma série.

> **Warning**
>
> **O `status` não faz round-trip.** Enviar `proposed`, `pending`, `arrived` ou `checked-in` e
> reler devolve `booked` — os quatro colapsam na mesma situação. Não construa fluxo em cima de
> distinguir "confirmado" de "paciente chegou": a plataforma não guarda essa diferença.

> **Warning**
>
> **`waitlist` e `entered-in-error` recusam a chamada.** Eles não têm destino na plataforma, e a
> recusa vem como `not-supported`, apontando `Appointment.status`.
>
> E `waitlist` é justamente um valor que a **leitura** devolve, num agendamento marcado como
> indisponível pela equipe. Ou seja: **há agendamentos que você lê e não consegue reenviar.**

> **Note**
>
> `proposed` é aceito na escrita, mas não faz o que parece: ele **não** cria um agendamento
> liberado, vira um agendamento normal. Liberar horário para o paciente marcar é ação da equipe na
> tela.
>
> `waitlist` é o único valor que a leitura devolve e a escrita não aceita.

### Os participantes

`participant` precisa de **exatamente um** de cada tipo, e o `type` do `actor` é o que
distingue:

```json
"participant": [
  { "status": "accepted",
    "actor": { "type": "Patient",
               "identifier": { "system": "https://www.acmesaude.com.br/integracao/paciente/",
                               "value": "507823709" } } },
  { "status": "accepted",
    "actor": { "type": "Practitioner",
               "identifier": { "system": "https://www.acmesaude.com.br/integracao/profissional/",
                               "value": "5032932" } } }
]
```

> **Warning**
>
> **Zero ou dois participantes do mesmo tipo recusam a chamada**, com uma mensagem que nomeia o
> tipo que faltou. Um agendamento com dois profissionais, ou sem paciente, não é possível.
>
> E o `type` é **obrigatório**: sem ele a API não sabe qual é qual, e a chamada é recusada como
> se o participante não existisse.

> **Note**
>
> `participant[].status` é exigido pelo FHIR e **descartado na escrita**: a leitura devolve sempre
> `accepted`, nos dois participantes. Não há como registrar que o paciente ainda não confirmou.

### A modalidade

`appointmentType` diz se a consulta é online ou presencial, num `coding` cujo `system` é
`{host}/fhir/resources/CodeSystem/appointment-type` — a URL absoluta do seu ambiente, como
`https://landing-zone-api.nilo.services/fhir/resources/CodeSystem/appointment-type` em produção:

| `code`      | Modalidade             |
| ----------- | ---------------------- |
| `ONLINE`    | Atendimento online     |
| `IN_PERSON` | Atendimento presencial |

> **Warning**
>
> **Omitir `appointmentType` cria um agendamento online**, não um sem modalidade. Se a consulta é
> presencial, mande o `IN_PERSON` — a omissão não é neutra.
>
> Um `coding` em outro `system` é **ignorado em silêncio** e cai na mesma regra da omissão — e é
> por isso que errar a URL do `system` é perigoso: a consulta presencial vira online e a chamada
> responde `200`. Já um código desconhecido **dentro** do `system` da Nilo recusa a chamada com
> `not-supported`.

### A sala de vídeo

Nos agendamentos online com sala criada, o link vem embutido no próprio recurso, em
`contained[0].address`:

```json
"contained": [
  { "resourceType": "Endpoint",
    "status": "active",
    "address": "https://video.nilo.services/r/9f2c41a8",
    "connectionType": { "code": "https" },
    "payloadType": [{ "text": "video" }] }
]
```

> **Note**
>
> É **só resposta**: enviar um `contained` não cria sala — embora o que você mandar fique gravado
> e volte nas leituras seguintes, sem significar nada.

> **Warning**
>
> **A sala não nasce com o agendamento, e nem todo agendamento tem uma.** Três coisas precisam ser
> verdade:
>
> * a funcionalidade tem de estar **habilitada para o seu ambiente**, o que é decidido na
>   implantação. Se ela não estiver, nenhum agendamento terá sala — fale com o **Suporte**;
> * o agendamento tem de ter **datas no futuro**: um agendamento retroativo não gera sala;
> * a situação tem de ser de agendamento em aberto: `fulfilled`, `noshow` e `cancelled` não geram
>   sala.
>
> E a criação é **assíncrona**. A resposta do `POST` normalmente vem **sem** `contained`; a sala
> aparece em segundos, podendo levar alguns minutos em períodos de alta demanda. Prefira ser
> avisado por webhook a ficar consultando — e não conclua que o agendamento não terá sala só
> porque a primeira leitura veio sem ela.

### Campos que a Nilo não usa

O `Appointment` canônico traz muito mais do que esta integração lê: `cancelationReason`,
`serviceCategory`, `serviceType`, `specialty`, `reasonCode`, `reasonReference`, `priority`,
`supportingInformation`, `minutesDuration`, `slot`, `basedOn`, `requestedPeriod` e
`patientInstruction`. Nenhum deles é lido.

> **Warning**
>
> Repare em **`cancelationReason`**: não há como registrar **por que** um agendamento foi
> cancelado. E em **`specialty`**: a especialidade do agendamento existe na tela e não tem campo
> aqui.

> **Note**
>
> A referência lista só os campos suportados, e é assim que ela deve ser lida: **o que mandar na
> escrita**. A API em si é mais tolerante — o que você mandar a mais fica guardado no recurso e
> volta nas leituras seguintes, sem nunca ter significado nada para a plataforma. Se o seu
> validador for estrito contra a referência, uma resposta assim vai parecer inválida; o remédio é
> não enviá-los.

## Marcar um agendamento

**`Requisição — Agendar uma consulta online`**

```json title="Requisição — Agendar uma consulta online"
{
  "resourceType": "Appointment",
  "identifier": [
    {
      "use": "usual",
      "system": "https://www.acmesaude.com.br/integracao/agendamento/",
      "value": "AG-3001"
    }
  ],
  "status": "booked",
  "description": "Consulta de retorno — endocrinologia",
  "comment": "Paciente pediu horário no fim da tarde.",
  "start": "2026-06-15T14:00:00+00:00",
  "end": "2026-06-15T14:30:00+00:00",
  "appointmentType": {
    "coding": [
      {
        "system": "https://landing-zone-api.nilo.services/fhir/resources/CodeSystem/appointment-type",
        "code": "ONLINE"
      }
    ]
  },
  "participant": [
    {
      "status": "accepted",
      "actor": {
        "type": "Patient",
        "identifier": {
          "use": "usual",
          "system": "https://www.acmesaude.com.br/integracao/paciente/",
          "value": "507823709"
        }
      }
    },
    {
      "status": "accepted",
      "actor": {
        "type": "Practitioner",
        "identifier": {
          "use": "usual",
          "system": "https://www.acmesaude.com.br/integracao/profissional/",
          "value": "5032932"
        }
      }
    }
  ]
}
```

A resposta é o recurso gravado, sem envelope:

### Response (200)

```json
{
  "resourceType": "Appointment",
  "identifier": [
    {
      "system": "https://landing-zone-api.nilo.services/fhir/resources/NamingSystem/care-api--scheduling-v2",
      "value": "620914",
      "use": "usual"
    },
    {
      "system": "https://www.acmesaude.com.br/integracao/agendamento/",
      "value": "AG-3001",
      "use": "usual"
    }
  ],
  "status": "booked",
  "participant": [
    {
      "actor": {
        "identifier": {
          "system": "https://www.acmesaude.com.br/integracao/paciente/",
          "value": "507823709",
          "use": "usual"
        },
        "type": "Patient",
        "reference": "Patient/ba200cfa-dae0-46cf-81a0-008e3f7414b4"
      },
      "status": "accepted"
    },
    {
      "actor": {
        "identifier": {
          "system": "https://www.acmesaude.com.br/integracao/profissional/",
          "value": "5032932",
          "use": "usual"
        },
        "type": "Practitioner",
        "reference": "Practitioner/1f30c8b7-45ad-4e62-9c81-73b0e5f24a19"
      },
      "status": "accepted"
    }
  ],
  "id": "8f30c26b-5d17-4e94-a1c3-70b6e2854f19",
  "meta": {
    "lastUpdated": "2026-06-01T09:12:45.208000Z",
    "versionId": "MTc4NjAyMTQ1MjkwNTAwMDM2Nw"
  },
  "start": "2026-06-15T14:00:00+00:00",
  "end": "2026-06-15T14:30:00+00:00",
  "description": "Consulta de retorno — endocrinologia",
  "comment": "Paciente pediu horário no fim da tarde.",
  "appointmentType": {
    "coding": [
      {
        "system": "https://landing-zone-api.nilo.services/fhir/resources/CodeSystem/appointment-type",
        "code": "ONLINE",
        "display": "Atendimento Online"
      }
    ]
  },
  "extension": [
    {
      "url": "https://landing-zone-api.nilo.services/fhir/resources/StructureDefinition/appointment-allowConflict",
      "valueBoolean": false
    }
  ],
  "created": "2026-06-01T09:12:44+00:00"
}
```

Guarde o `id`: é por ele que se faz a leitura direta. Ao lado do seu `identifier`, a resposta
traz o identificador Nilo do agendamento, no `system`
`…/NamingSystem/care-api--scheduling-v2`.

**`Requisição — Agendar uma consulta presencial`**

```json title="Requisição — Agendar uma consulta presencial"
{
  "resourceType": "Appointment",
  "identifier": [
    {
      "use": "usual",
      "system": "https://www.acmesaude.com.br/integracao/agendamento/",
      "value": "AG-3002"
    }
  ],
  "status": "booked",
  "description": "Consulta inicial — nutrição",
  "start": "2026-06-16T09:00:00+00:00",
  "end": "2026-06-16T09:40:00+00:00",
  "appointmentType": {
    "coding": [
      {
        "system": "https://landing-zone-api.nilo.services/fhir/resources/CodeSystem/appointment-type",
        "code": "IN_PERSON"
      }
    ]
  },
  "participant": [
    {
      "status": "accepted",
      "actor": {
        "type": "Patient",
        "identifier": {
          "use": "usual",
          "system": "https://www.acmesaude.com.br/integracao/paciente/",
          "value": "507823709"
        }
      }
    },
    {
      "status": "accepted",
      "actor": {
        "type": "Practitioner",
        "identifier": {
          "use": "usual",
          "system": "https://www.acmesaude.com.br/integracao/profissional/",
          "value": "5032932"
        }
      }
    }
  ]
}
```

## Cancelar

Cancelar é reenviar o mesmo `identifier` com `status: cancelled`.

**`Requisição — Cancelar um agendamento`**

```json title="Requisição — Cancelar um agendamento"
{
  "resourceType": "Appointment",
  "identifier": [
    {
      "use": "usual",
      "system": "https://www.acmesaude.com.br/integracao/agendamento/",
      "value": "AG-3001"
    }
  ],
  "status": "cancelled",
  "description": "Consulta de retorno — endocrinologia",
  "comment": "Paciente pediu horário no fim da tarde.",
  "start": "2026-06-15T14:00:00+00:00",
  "end": "2026-06-15T14:30:00+00:00",
  "appointmentType": {
    "coding": [
      {
        "system": "https://landing-zone-api.nilo.services/fhir/resources/CodeSystem/appointment-type",
        "code": "ONLINE"
      }
    ]
  },
  "participant": [
    {
      "status": "accepted",
      "actor": {
        "type": "Patient",
        "identifier": {
          "use": "usual",
          "system": "https://www.acmesaude.com.br/integracao/paciente/",
          "value": "507823709"
        }
      }
    },
    {
      "status": "accepted",
      "actor": {
        "type": "Practitioner",
        "identifier": {
          "use": "usual",
          "system": "https://www.acmesaude.com.br/integracao/profissional/",
          "value": "5032932"
        }
      }
    }
  ]
}
```

> **Warning**
>
> **Não há atualização parcial.** Todo `POST` monta o agendamento inteiro a partir do payload, e
> o que você omitir é apagado **na plataforma** ou volta ao padrão: sem `comment`, as observações
> somem da ficha; sem `appointmentType`, um agendamento presencial vira **online**.
>
> Reenvie o recurso inteiro em toda atualização, inclusive no cancelamento.

> **Warning**
>
> **E a leitura não acompanha esse apagamento.** O recurso FHIR guarda o último valor não vazio:
> depois de um `POST` sem `comment`, a consulta continua devolvendo a observação **antiga**, que a
> equipe já não vê. Para zerar de verdade os dois lados, mande o campo vazio (`"comment": ""`) em
> vez de omiti-lo.

> **Note**
>
> Não há remoção por integração: este endpoint nunca responde `204`. Cancelar é a forma de
> encerrar um agendamento.

> **Note**
>
> Ao cancelar, a plataforma pode **limpar as datas** do registro. Um agendamento com
> `status: cancelled` lido depois disso pode vir sem `start` e sem `end` — não trate a ausência
> como erro de leitura.

## Buscar

### Request

GET [https://landing-zone-api.nilo.services/fhir/resources/Appointment](https://landing-zone-api.nilo.services/fhir/resources/Appointment)

**`Busca com resultados`**

```curl Busca com resultados
curl -G https://landing-zone-api.nilo.services/fhir/resources/Appointment \
     -H "x-api-key: <apiKey>" \
     -d _count=50 \
     -d _lastUpdated=eq2013-01-14 \
     --data-urlencode appointment-type=https://landing-zone-api.nilo.services/fhir/resources/CodeSystem/appointment-type|ONLINE \
     -d date=ge2026-06-01 \
     --data-urlencode identifier=https://www.acmesaude.com.br/integracao/agendamento/|AG-3001 \
     --data-urlencode patient=Patient/ba200cfa-dae0-46cf-81a0-008e3f7414b4 \
     --data-urlencode patient:identifier=https://www.acmesaude.com.br/integracao/paciente/|507823709 \
     --data-urlencode practitioner=Practitioner/1f30c8b7-45ad-4e62-9c81-73b0e5f24a19 \
     --data-urlencode practitioner:identifier=https://www.acmesaude.com.br/integracao/profissional/|5032932 \
     -d status=booked
```

**`Busca com resultados`**

```python Busca com resultados
import requests

url = "https://landing-zone-api.nilo.services/fhir/resources/Appointment"

querystring = {"_count":"50","_lastUpdated":"[\"eq2013-01-14\"]","appointment-type":"https://landing-zone-api.nilo.services/fhir/resources/CodeSystem/appointment-type|ONLINE","date":"ge2026-06-01","identifier":"https://www.acmesaude.com.br/integracao/agendamento/|AG-3001","patient":"Patient/ba200cfa-dae0-46cf-81a0-008e3f7414b4","patient:identifier":"https://www.acmesaude.com.br/integracao/paciente/|507823709","practitioner":"Practitioner/1f30c8b7-45ad-4e62-9c81-73b0e5f24a19","practitioner:identifier":"https://www.acmesaude.com.br/integracao/profissional/|5032932","status":"booked"}

headers = {"x-api-key": "<apiKey>"}

response = requests.get(url, headers=headers, params=querystring)

print(response.json())
```

**`Busca com resultados`**

```javascript Busca com resultados
const url = 'https://landing-zone-api.nilo.services/fhir/resources/Appointment?_count=50&_lastUpdated=%5B%22eq2013-01-14%22%5D&appointment-type=https%3A%2F%2Flanding-zone-api.nilo.services%2Ffhir%2Fresources%2FCodeSystem%2Fappointment-type%7CONLINE&date=ge2026-06-01&identifier=https%3A%2F%2Fwww.acmesaude.com.br%2Fintegracao%2Fagendamento%2F%7CAG-3001&patient=Patient%2Fba200cfa-dae0-46cf-81a0-008e3f7414b4&patient%3Aidentifier=https%3A%2F%2Fwww.acmesaude.com.br%2Fintegracao%2Fpaciente%2F%7C507823709&practitioner=Practitioner%2F1f30c8b7-45ad-4e62-9c81-73b0e5f24a19&practitioner%3Aidentifier=https%3A%2F%2Fwww.acmesaude.com.br%2Fintegracao%2Fprofissional%2F%7C5032932&status=booked';
const options = {method: 'GET', headers: {'x-api-key': '<apiKey>'}};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

**`Busca com resultados`**

```go Busca com resultados
package main

import (
	"fmt"
	"net/http"
	"io"
)

func main() {

	url := "https://landing-zone-api.nilo.services/fhir/resources/Appointment?_count=50&_lastUpdated=%5B%22eq2013-01-14%22%5D&appointment-type=https%3A%2F%2Flanding-zone-api.nilo.services%2Ffhir%2Fresources%2FCodeSystem%2Fappointment-type%7CONLINE&date=ge2026-06-01&identifier=https%3A%2F%2Fwww.acmesaude.com.br%2Fintegracao%2Fagendamento%2F%7CAG-3001&patient=Patient%2Fba200cfa-dae0-46cf-81a0-008e3f7414b4&patient%3Aidentifier=https%3A%2F%2Fwww.acmesaude.com.br%2Fintegracao%2Fpaciente%2F%7C507823709&practitioner=Practitioner%2F1f30c8b7-45ad-4e62-9c81-73b0e5f24a19&practitioner%3Aidentifier=https%3A%2F%2Fwww.acmesaude.com.br%2Fintegracao%2Fprofissional%2F%7C5032932&status=booked"

	req, _ := http.NewRequest("GET", url, nil)

	req.Header.Add("x-api-key", "<apiKey>")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

**`Busca com resultados`**

```ruby Busca com resultados
require 'uri'
require 'net/http'

url = URI("https://landing-zone-api.nilo.services/fhir/resources/Appointment?_count=50&_lastUpdated=%5B%22eq2013-01-14%22%5D&appointment-type=https%3A%2F%2Flanding-zone-api.nilo.services%2Ffhir%2Fresources%2FCodeSystem%2Fappointment-type%7CONLINE&date=ge2026-06-01&identifier=https%3A%2F%2Fwww.acmesaude.com.br%2Fintegracao%2Fagendamento%2F%7CAG-3001&patient=Patient%2Fba200cfa-dae0-46cf-81a0-008e3f7414b4&patient%3Aidentifier=https%3A%2F%2Fwww.acmesaude.com.br%2Fintegracao%2Fpaciente%2F%7C507823709&practitioner=Practitioner%2F1f30c8b7-45ad-4e62-9c81-73b0e5f24a19&practitioner%3Aidentifier=https%3A%2F%2Fwww.acmesaude.com.br%2Fintegracao%2Fprofissional%2F%7C5032932&status=booked")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Get.new(url)
request["x-api-key"] = '<apiKey>'

response = http.request(request)
puts response.read_body
```

**`Busca com resultados`**

```java Busca com resultados
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.get("https://landing-zone-api.nilo.services/fhir/resources/Appointment?_count=50&_lastUpdated=%5B%22eq2013-01-14%22%5D&appointment-type=https%3A%2F%2Flanding-zone-api.nilo.services%2Ffhir%2Fresources%2FCodeSystem%2Fappointment-type%7CONLINE&date=ge2026-06-01&identifier=https%3A%2F%2Fwww.acmesaude.com.br%2Fintegracao%2Fagendamento%2F%7CAG-3001&patient=Patient%2Fba200cfa-dae0-46cf-81a0-008e3f7414b4&patient%3Aidentifier=https%3A%2F%2Fwww.acmesaude.com.br%2Fintegracao%2Fpaciente%2F%7C507823709&practitioner=Practitioner%2F1f30c8b7-45ad-4e62-9c81-73b0e5f24a19&practitioner%3Aidentifier=https%3A%2F%2Fwww.acmesaude.com.br%2Fintegracao%2Fprofissional%2F%7C5032932&status=booked")
  .header("x-api-key", "<apiKey>")
  .asString();
```

**`Busca com resultados`**

```php Busca com resultados
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('GET', 'https://landing-zone-api.nilo.services/fhir/resources/Appointment?_count=50&_lastUpdated=%5B%22eq2013-01-14%22%5D&appointment-type=https%3A%2F%2Flanding-zone-api.nilo.services%2Ffhir%2Fresources%2FCodeSystem%2Fappointment-type%7CONLINE&date=ge2026-06-01&identifier=https%3A%2F%2Fwww.acmesaude.com.br%2Fintegracao%2Fagendamento%2F%7CAG-3001&patient=Patient%2Fba200cfa-dae0-46cf-81a0-008e3f7414b4&patient%3Aidentifier=https%3A%2F%2Fwww.acmesaude.com.br%2Fintegracao%2Fpaciente%2F%7C507823709&practitioner=Practitioner%2F1f30c8b7-45ad-4e62-9c81-73b0e5f24a19&practitioner%3Aidentifier=https%3A%2F%2Fwww.acmesaude.com.br%2Fintegracao%2Fprofissional%2F%7C5032932&status=booked', [
  'headers' => [
    'x-api-key' => '<apiKey>',
  ],
]);

echo $response->getBody();
```

**`Busca com resultados`**

```csharp Busca com resultados
using RestSharp;

var client = new RestClient("https://landing-zone-api.nilo.services/fhir/resources/Appointment?_count=50&_lastUpdated=%5B%22eq2013-01-14%22%5D&appointment-type=https%3A%2F%2Flanding-zone-api.nilo.services%2Ffhir%2Fresources%2FCodeSystem%2Fappointment-type%7CONLINE&date=ge2026-06-01&identifier=https%3A%2F%2Fwww.acmesaude.com.br%2Fintegracao%2Fagendamento%2F%7CAG-3001&patient=Patient%2Fba200cfa-dae0-46cf-81a0-008e3f7414b4&patient%3Aidentifier=https%3A%2F%2Fwww.acmesaude.com.br%2Fintegracao%2Fpaciente%2F%7C507823709&practitioner=Practitioner%2F1f30c8b7-45ad-4e62-9c81-73b0e5f24a19&practitioner%3Aidentifier=https%3A%2F%2Fwww.acmesaude.com.br%2Fintegracao%2Fprofissional%2F%7C5032932&status=booked");
var request = new RestRequest(Method.GET);
request.AddHeader("x-api-key", "<apiKey>");
IRestResponse response = client.Execute(request);
```

**`Busca com resultados`**

```swift Busca com resultados
import Foundation

let headers = ["x-api-key": "<apiKey>"]

let request = NSMutableURLRequest(url: NSURL(string: "https://landing-zone-api.nilo.services/fhir/resources/Appointment?_count=50&_lastUpdated=%5B%22eq2013-01-14%22%5D&appointment-type=https%3A%2F%2Flanding-zone-api.nilo.services%2Ffhir%2Fresources%2FCodeSystem%2Fappointment-type%7CONLINE&date=ge2026-06-01&identifier=https%3A%2F%2Fwww.acmesaude.com.br%2Fintegracao%2Fagendamento%2F%7CAG-3001&patient=Patient%2Fba200cfa-dae0-46cf-81a0-008e3f7414b4&patient%3Aidentifier=https%3A%2F%2Fwww.acmesaude.com.br%2Fintegracao%2Fpaciente%2F%7C507823709&practitioner=Practitioner%2F1f30c8b7-45ad-4e62-9c81-73b0e5f24a19&practitioner%3Aidentifier=https%3A%2F%2Fwww.acmesaude.com.br%2Fintegracao%2Fprofissional%2F%7C5032932&status=booked")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "GET"
request.allHTTPHeaderFields = headers

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```

A resposta é sempre um `Bundle` do tipo `searchset`:

### Response (200)

```json
{
  "resourceType": "Bundle",
  "type": "searchset",
  "entry": [
    {
      "fullUrl": "https://landing-zone-api.nilo.services/fhir/resources/Appointment/8f30c26b-5d17-4e94-a1c3-70b6e2854f19",
      "resource": {
        "resourceType": "Appointment",
        "identifier": [
          {
            "system": "https://landing-zone-api.nilo.services/fhir/resources/NamingSystem/care-api--scheduling-v2",
            "value": "620914",
            "use": "usual"
          },
          {
            "system": "https://www.acmesaude.com.br/integracao/agendamento/",
            "value": "AG-3001",
            "use": "usual"
          }
        ],
        "status": "booked",
        "participant": [
          {
            "actor": {
              "identifier": {
                "system": "https://www.acmesaude.com.br/integracao/paciente/",
                "value": "507823709",
                "use": "usual"
              },
              "type": "Patient",
              "reference": "Patient/ba200cfa-dae0-46cf-81a0-008e3f7414b4"
            },
            "status": "accepted"
          },
          {
            "actor": {
              "identifier": {
                "system": "https://www.acmesaude.com.br/integracao/profissional/",
                "value": "5032932",
                "use": "usual"
              },
              "type": "Practitioner",
              "reference": "Practitioner/1f30c8b7-45ad-4e62-9c81-73b0e5f24a19"
            },
            "status": "accepted"
          }
        ],
        "id": "8f30c26b-5d17-4e94-a1c3-70b6e2854f19",
        "meta": {
          "lastUpdated": "2026-06-01T09:12:45.208000Z",
          "versionId": "MTc4NjAyMTQ1MjkwNTAwMDM2Nw"
        },
        "start": "2026-06-15T14:00:00+00:00",
        "end": "2026-06-15T14:30:00+00:00",
        "description": "Consulta de retorno — endocrinologia",
        "comment": "Paciente pediu horário no fim da tarde.",
        "appointmentType": {
          "coding": [
            {
              "system": "https://landing-zone-api.nilo.services/fhir/resources/CodeSystem/appointment-type",
              "code": "ONLINE",
              "display": "Atendimento Online"
            }
          ]
        },
        "created": "2026-06-01T09:12:44+00:00",
        "contained": [
          {
            "resourceType": "Endpoint",
            "address": "https://video.nilo.services/r/9f2c41a8",
            "status": "active",
            "connectionType": {
              "code": "https"
            },
            "payloadType": [
              {
                "text": "video"
              }
            ]
          }
        ]
      },
      "search": {
        "mode": "match"
      }
    },
    {
      "fullUrl": "https://landing-zone-api.nilo.services/fhir/resources/Appointment/1d74b8e0-92a6-4c15-830f-4e5a7c93d268",
      "resource": {
        "resourceType": "Appointment",
        "identifier": [
          {
            "system": "https://landing-zone-api.nilo.services/fhir/resources/NamingSystem/care-api--scheduling-v2",
            "value": "620915",
            "use": "usual"
          }
        ],
        "status": "fulfilled",
        "participant": [
          {
            "actor": {
              "identifier": {
                "system": "https://www.acmesaude.com.br/integracao/paciente/",
                "value": "507823709",
                "use": "usual"
              },
              "type": "Patient",
              "reference": "Patient/ba200cfa-dae0-46cf-81a0-008e3f7414b4"
            },
            "status": "accepted"
          },
          {
            "actor": {
              "identifier": {
                "system": "https://www.acmesaude.com.br/integracao/profissional/",
                "value": "5032932",
                "use": "usual"
              },
              "type": "Practitioner",
              "reference": "Practitioner/1f30c8b7-45ad-4e62-9c81-73b0e5f24a19"
            },
            "status": "accepted"
          }
        ],
        "id": "1d74b8e0-92a6-4c15-830f-4e5a7c93d268",
        "meta": {
          "lastUpdated": "2026-06-02T11:40:02.774000Z",
          "versionId": "MTc4NjAyMTQ1MjkwNTAwMDM5OA"
        },
        "start": "2026-06-02T10:00:00+00:00",
        "end": "2026-06-02T10:40:00+00:00",
        "description": "Consulta inicial — nutrição",
        "appointmentType": {
          "coding": [
            {
              "system": "https://landing-zone-api.nilo.services/fhir/resources/CodeSystem/appointment-type",
              "code": "IN_PERSON",
              "display": "Atendimento Presencial"
            }
          ]
        },
        "created": "2026-05-20T15:03:11+00:00"
      },
      "search": {
        "mode": "match"
      }
    }
  ],
  "link": []
}
```

Busca sem resultados não é erro: volta `200` com um `Bundle` cujo `entry` é uma lista vazia.

### Response (200)

```json
{
  "resourceType": "Bundle",
  "type": "searchset",
  "entry": [],
  "link": []
}
```

### Parâmetros de busca suportados

| Nome                      | Tipo                                                       | Descrição                                                          | Expressão                                  |
| ------------------------- | ---------------------------------------------------------- | ------------------------------------------------------------------ | ------------------------------------------ |
| `identifier`              | [token](https://hl7.org/fhir/R4/search.html#token)         | Identificador do agendamento, em `system\|value`                   | `Appointment.identifier`                   |
| `patient`                 | [reference](https://hl7.org/fhir/R4/search.html#reference) | Paciente, pelo `id` Nilo FHIR dele                                 | `Appointment.participant.actor`            |
| `patient:identifier`      | [reference](https://hl7.org/fhir/R4/search.html#reference) | Paciente, pelo identificador dele                                  | `Appointment.participant.actor.identifier` |
| `practitioner`            | [reference](https://hl7.org/fhir/R4/search.html#reference) | Profissional, pelo `id` Nilo FHIR dele                             | `Appointment.participant.actor`            |
| `practitioner:identifier` | [reference](https://hl7.org/fhir/R4/search.html#reference) | Profissional, pelo identificador dele                              | `Appointment.participant.actor.identifier` |
| `date`                    | [date](https://hl7.org/fhir/R4/search.html#date)           | Data do agendamento, com os prefixos `eq`, `ge`, `le`              | `Appointment.start`                        |
| `status`                  | [token](https://hl7.org/fhir/R4/search.html#token)         | Situação                                                           | `Appointment.status`                       |
| `appointment-type`        | [token](https://hl7.org/fhir/R4/search.html#token)         | Modalidade, em `system\|code`                                      | `Appointment.appointmentType`              |
| `_lastUpdated`            | [date](https://hl7.org/fhir/R4/search.html#date)           | Data da última gravação no store, com os prefixos `eq`, `ge`, `le` | —                                          |

> **Note**
>
> Os demais parâmetros canônicos do `Appointment` — `service-category`, `service-type`,
> `specialty`, `reason-code`, `reason-reference`, `slot`, `based-on` e `supporting-info` — só
> encontram o que **você mesmo** tiver enviado: a plataforma não preenche nenhum desses campos,
> mas guarda o que vier no payload.
>
> `part-status` é a exceção pelo motivo oposto: como todo participante é gravado como `accepted`,
> `part-status=accepted` devolve **tudo**. Não é filtro útil.

> **Warning**
>
> Qual identificador as referências de `participant.actor` carregam **depende da sua
> implantação**. Na configuração que usa identificadores externos, cada referência sai com o
> identificador do seu sistema; sem ela, vem o identificador Nilo do paciente e do profissional. É
> esse `system` que você tem de usar no filtro. Confira numa resposta de leitura qual dos dois está
> lá antes de montar a busca em volume.

A paginação é por `_count` e `_page_token`; havendo página seguinte, o `Bundle` traz a URL
pronta em `link`.

## Ler por ID

### Request

GET [https://landing-zone-api.nilo.services/fhir/resources/Appointment/\{id}](https://landing-zone-api.nilo.services/fhir/resources/Appointment/\{id})

**`Agendamento encontrado`**

```curl Agendamento encontrado
curl https://landing-zone-api.nilo.services/fhir/resources/Appointment/id \
     -H "x-api-key: <apiKey>"
```

**`Agendamento encontrado`**

```python Agendamento encontrado
import requests

url = "https://landing-zone-api.nilo.services/fhir/resources/Appointment/id"

headers = {"x-api-key": "<apiKey>"}

response = requests.get(url, headers=headers)

print(response.json())
```

**`Agendamento encontrado`**

```javascript Agendamento encontrado
const url = 'https://landing-zone-api.nilo.services/fhir/resources/Appointment/id';
const options = {method: 'GET', headers: {'x-api-key': '<apiKey>'}};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

**`Agendamento encontrado`**

```go Agendamento encontrado
package main

import (
	"fmt"
	"net/http"
	"io"
)

func main() {

	url := "https://landing-zone-api.nilo.services/fhir/resources/Appointment/id"

	req, _ := http.NewRequest("GET", url, nil)

	req.Header.Add("x-api-key", "<apiKey>")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

**`Agendamento encontrado`**

```ruby Agendamento encontrado
require 'uri'
require 'net/http'

url = URI("https://landing-zone-api.nilo.services/fhir/resources/Appointment/id")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Get.new(url)
request["x-api-key"] = '<apiKey>'

response = http.request(request)
puts response.read_body
```

**`Agendamento encontrado`**

```java Agendamento encontrado
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.get("https://landing-zone-api.nilo.services/fhir/resources/Appointment/id")
  .header("x-api-key", "<apiKey>")
  .asString();
```

**`Agendamento encontrado`**

```php Agendamento encontrado
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('GET', 'https://landing-zone-api.nilo.services/fhir/resources/Appointment/id', [
  'headers' => [
    'x-api-key' => '<apiKey>',
  ],
]);

echo $response->getBody();
```

**`Agendamento encontrado`**

```csharp Agendamento encontrado
using RestSharp;

var client = new RestClient("https://landing-zone-api.nilo.services/fhir/resources/Appointment/id");
var request = new RestRequest(Method.GET);
request.AddHeader("x-api-key", "<apiKey>");
IRestResponse response = client.Execute(request);
```

**`Agendamento encontrado`**

```swift Agendamento encontrado
import Foundation

let headers = ["x-api-key": "<apiKey>"]

let request = NSMutableURLRequest(url: NSURL(string: "https://landing-zone-api.nilo.services/fhir/resources/Appointment/id")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "GET"
request.allHTTPHeaderFields = headers

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```

> **Warning**
>
> Diferente da busca, esta leitura não devolve um `Bundle` — mas também **não devolve o recurso
> nu**. A resposta é um envelope com `fullUrl`, `search` e `resource`, e o agendamento está em
> `resource`. Ler `start` ou `participant` na raiz da resposta não encontra nada.

### Response (200)

```json
{
  "fullUrl": "https://landing-zone-api.nilo.services/fhir/resources/Appointment/8f30c26b-5d17-4e94-a1c3-70b6e2854f19",
  "resource": {
    "resourceType": "Appointment",
    "identifier": [
      {
        "system": "https://landing-zone-api.nilo.services/fhir/resources/NamingSystem/care-api--scheduling-v2",
        "value": "620914",
        "use": "usual"
      }
    ],
    "status": "booked",
    "participant": [
      {
        "actor": {
          "identifier": {
            "system": "https://www.acmesaude.com.br/integracao/paciente/",
            "value": "507823709",
            "use": "usual"
          },
          "type": "Patient",
          "reference": "Patient/ba200cfa-dae0-46cf-81a0-008e3f7414b4"
        },
        "status": "accepted"
      },
      {
        "actor": {
          "identifier": {
            "system": "https://www.acmesaude.com.br/integracao/profissional/",
            "value": "5032932",
            "use": "usual"
          },
          "type": "Practitioner",
          "reference": "Practitioner/1f30c8b7-45ad-4e62-9c81-73b0e5f24a19"
        },
        "status": "accepted"
      }
    ],
    "id": "8f30c26b-5d17-4e94-a1c3-70b6e2854f19",
    "meta": {
      "lastUpdated": "2026-06-01T09:12:45.208000Z",
      "versionId": "MTc4NjAyMTQ1MjkwNTAwMDM2Nw"
    },
    "start": "2026-06-15T14:00:00+00:00",
    "end": "2026-06-15T14:30:00+00:00",
    "description": "Consulta de retorno — endocrinologia",
    "created": "2026-06-01T09:12:44+00:00"
  },
  "search": {
    "mode": "match"
  }
}
```

## Efeitos colaterais

> **Warning**
>
> **Um agendamento apagado na plataforma some do store.** A busca para de devolvê-lo e a leitura
> por `id` passa a responder `404`, sem aviso. Não conclua que ele foi cancelado — um cancelamento
> devolve `status: cancelled`, não um `404`.
>
> O mesmo acontece, mais raramente, quando o agendamento fica **sem situação registrada** ou com
> uma situação que esta integração não conhece: o recurso é removido em silêncio na sincronização
> seguinte.

> **Note**
>
> Marcar um agendamento **não cria um atendimento**. O atendimento nasce quando a consulta
> acontece — veja [Atendimentos](/guia/recursos/encounter).

> **Note**
>
> O profissional que você informa em `participant` fica registrado também como **autor** e como
> **responsável pelo agendamento** na plataforma. Não há como separar quem atende de quem marcou.

> **Note**
>
> Um agendamento marcado por integração aparece na agenda do profissional como qualquer outro, e
> a equipe pode alterá-lo por lá. Uma alteração feita na tela chega às suas leituras seguintes.

## Erros

Recusa é `400`, e o corpo é um `OperationOutcome`: `issue[].expression` aponta o campo culpado
e `issue[].details.text` explica o motivo. A exceção é o `409` da agenda duplicada.

| Status | `code`          | `expression`                    | Mensagem                                                                                                     | Quando                                                                                              |
| ------ | --------------- | ------------------------------- | ------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------- |
| `400`  | `required`      | `Appointment.identifier`        | `Field is required`                                                                                          | O payload não tem `identifier`                                                                      |
| `400`  | `business-rule` | `Appointment.identifier`        | `Unable to use any of the provided identifiers to match an existing resource, which can lead to duplicates.` | Há `identifier`, mas nenhum utilizável                                                              |
| `400`  | `required`      | `Appointment.participant.actor` | `Appointment must have only one participant.actor of type Patient`                                           | Falta o paciente, ou vem mais de um                                                                 |
| `400`  | `required`      | `Appointment.participant.actor` | `Appointment must have only one participant.actor of type Practitioner`                                      | Falta o profissional, ou vem mais de um                                                             |
| `400`  | `not-found`     | `Appointment.participant.actor` | `Unable to find Patient` · `Unable to find Practitioner`                                                     | O identificador não resolve para alguém do seu ambiente                                             |
| `400`  | `required`      | `Appointment.start`             | `The start field is required`                                                                                | O payload não tem `start`                                                                           |
| `400`  | `required`      | `Appointment.end`               | `The end field is required`                                                                                  | O payload não tem `end`                                                                             |
| `400`  | `invalid`       | `Appointment.end`               | `The end field must be greater than the start field`                                                         | O fim é menor ou igual ao início                                                                    |
| `400`  | `not-supported` | `Appointment.status`            | `The status '…' is not supported`                                                                            | `waitlist` ou `entered-in-error`                                                                    |
| `400`  | `not-supported` | `Appointment.appointmentType`   | `The appointment type code '…' is not supported`                                                             | Código de modalidade desconhecido no `system` da Nilo                                               |
| `400`  | `structure`     | —                               | `Resource has identifier from a Nilo environment that is not the current environment.`                       | O payload traz um identificador Nilo gerado em outro ambiente                                       |
| `400`  | `structure`     | o campo recusado                | mensagem da validação FHIR                                                                                   | O payload não é um `Appointment` válido — `status` ou `participant` ausentes, tipo errado num campo |
| `400`  | `exception`     | —                               | `HTTPBadRequest: …`                                                                                          | O horário colide com outro compromisso do profissional, ou está fora da grade de atendimento dele   |
| `409`  | `conflict`      | —                               | `Resource conflicts with other existing resource(s)`, mais um `diagnostics`                                  | Já existe agendamento do mesmo paciente, ou do mesmo profissional, começando naquele horário        |

> **Warning**
>
> **As duas últimas linhas são a conferência de agenda**, que a integração dispensa por padrão:
> elas só aparecem quando o `Appointment` enviado traz a extensão
> [`appointment-allowConflict`](#sobreposição-de-horário) com `false` e a configuração de
> sobreposição do care provider não está habilitada. Nenhuma das duas aponta
> `expression`: elas não são validações de um campo do payload, e sim da agenda como um todo.
>
> A linha `exception` não é uma validação desta API — é uma falha repassada como está, com uma
> mensagem de erro de linguagem que inclui o endereço interno chamado. O mesmo vale para o
> `diagnostics` do `409`.
>
> **Nada disso é contrato:** não tente interpretar o texto, não o exiba para o usuário final e não
> o registre em log de longa duração. Trate `code: exception` como "payload recusado, motivo não
> classificado" e confira o `start`, o `end` e o profissional.

**`Resposta 400 — Participantes fora do formato`**

```json title="Resposta 400 — Participantes fora do formato"
{
  "resourceType": "OperationOutcome",
  "issue": [
    {
      "severity": "error",
      "code": "required",
      "expression": [
        "Appointment.participant.actor"
      ],
      "details": {
        "text": "Appointment must have only one participant.actor of type Practitioner"
      }
    }
  ]
}
```

Os payloads completos estão na aba **Referência**, em `POST /fhir/resources/Appointment`.

## O que a integração não cobre

* o **motivo** do cancelamento;
* a **especialidade** e a **recorrência** do agendamento, que existem na tela;
* a distinção entre agendamento **liberado** e **marcado** na escrita — só na leitura;
* a **confirmação** do paciente: `participant[].status` é sempre `accepted`;
* criar a **sala de vídeo** — ela é criada pela plataforma.

Para a consulta prevista por uma diretriz, que antecede o agendamento, veja
[Consulta prevista](/guia/recursos/schedule); para o atendimento que acontece depois,
[Atendimentos](/guia/recursos/encounter).