> 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.

# Webhooks

> Receber uma chamada da Nilo quando um recurso muda, no padrão FHIR Subscription.

Um **webhook** é o caminho inverso da integração: em vez de você consultar a Nilo, a Nilo chama
você quando alguma coisa muda. Você registra uma URL e o tipo de recurso a observar, e passa a
receber uma requisição a cada alteração.

No FHIR isso é o recurso
[`Subscription`](https://hl7.org/fhir/R4/subscription.html).

> **Warning**
>
> **Só o canal `rest-hook` é suportado**, ou seja, uma chamada HTTP para uma URL sua. Os demais
> canais do FHIR — e-mail, mensagem, websocket — recusam a chamada.

## Criar uma assinatura

### Request

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

**`Criar uma assinatura`**

```curl Criar uma assinatura
curl -X POST https://landing-zone-api.nilo.services/fhir/resources/Subscription \
     -H "x-api-key: <apiKey>" \
     -H "Content-Type: application/json" \
     -d '{
  "resourceType": "Subscription",
  "status": "requested",
  "criteria": "Patient",
  "reason": "Sincronizar cadastro de pacientes",
  "channel": {
    "type": "rest-hook",
    "endpoint": "https://webhooks.acmesaude.com.br/nilo/fhir"
  }
}'
```

**`Criar uma assinatura`**

```python Criar uma assinatura
import requests

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

payload = {
    "resourceType": "Subscription",
    "status": "requested",
    "criteria": "Patient",
    "reason": "Sincronizar cadastro de pacientes",
    "channel": {
        "type": "rest-hook",
        "endpoint": "https://webhooks.acmesaude.com.br/nilo/fhir"
    }
}
headers = {
    "x-api-key": "<apiKey>",
    "Content-Type": "application/json"
}

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

print(response.json())
```

**`Criar uma assinatura`**

```javascript Criar uma assinatura
const url = 'https://landing-zone-api.nilo.services/fhir/resources/Subscription';
const options = {
  method: 'POST',
  headers: {'x-api-key': '<apiKey>', 'Content-Type': 'application/json'},
  body: '{"resourceType":"Subscription","status":"requested","criteria":"Patient","reason":"Sincronizar cadastro de pacientes","channel":{"type":"rest-hook","endpoint":"https://webhooks.acmesaude.com.br/nilo/fhir"}}'
};

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

**`Criar uma assinatura`**

```go Criar uma assinatura
package main

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

func main() {

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

	payload := strings.NewReader("{\n  \"resourceType\": \"Subscription\",\n  \"status\": \"requested\",\n  \"criteria\": \"Patient\",\n  \"reason\": \"Sincronizar cadastro de pacientes\",\n  \"channel\": {\n    \"type\": \"rest-hook\",\n    \"endpoint\": \"https://webhooks.acmesaude.com.br/nilo/fhir\"\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))

}
```

**`Criar uma assinatura`**

```ruby Criar uma assinatura
require 'uri'
require 'net/http'

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

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\": \"Subscription\",\n  \"status\": \"requested\",\n  \"criteria\": \"Patient\",\n  \"reason\": \"Sincronizar cadastro de pacientes\",\n  \"channel\": {\n    \"type\": \"rest-hook\",\n    \"endpoint\": \"https://webhooks.acmesaude.com.br/nilo/fhir\"\n  }\n}"

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

**`Criar uma assinatura`**

```java Criar uma assinatura
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/Subscription")
  .header("x-api-key", "<apiKey>")
  .header("Content-Type", "application/json")
  .body("{\n  \"resourceType\": \"Subscription\",\n  \"status\": \"requested\",\n  \"criteria\": \"Patient\",\n  \"reason\": \"Sincronizar cadastro de pacientes\",\n  \"channel\": {\n    \"type\": \"rest-hook\",\n    \"endpoint\": \"https://webhooks.acmesaude.com.br/nilo/fhir\"\n  }\n}")
  .asString();
```

**`Criar uma assinatura`**

```php Criar uma assinatura
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://landing-zone-api.nilo.services/fhir/resources/Subscription', [
  'body' => '{
  "resourceType": "Subscription",
  "status": "requested",
  "criteria": "Patient",
  "reason": "Sincronizar cadastro de pacientes",
  "channel": {
    "type": "rest-hook",
    "endpoint": "https://webhooks.acmesaude.com.br/nilo/fhir"
  }
}',
  'headers' => [
    'Content-Type' => 'application/json',
    'x-api-key' => '<apiKey>',
  ],
]);

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

**`Criar uma assinatura`**

```csharp Criar uma assinatura
using RestSharp;

var client = new RestClient("https://landing-zone-api.nilo.services/fhir/resources/Subscription");
var request = new RestRequest(Method.POST);
request.AddHeader("x-api-key", "<apiKey>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"resourceType\": \"Subscription\",\n  \"status\": \"requested\",\n  \"criteria\": \"Patient\",\n  \"reason\": \"Sincronizar cadastro de pacientes\",\n  \"channel\": {\n    \"type\": \"rest-hook\",\n    \"endpoint\": \"https://webhooks.acmesaude.com.br/nilo/fhir\"\n  }\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

**`Criar uma assinatura`**

```swift Criar uma assinatura
import Foundation

let headers = [
  "x-api-key": "<apiKey>",
  "Content-Type": "application/json"
]
let parameters = [
  "resourceType": "Subscription",
  "status": "requested",
  "criteria": "Patient",
  "reason": "Sincronizar cadastro de pacientes",
  "channel": [
    "type": "rest-hook",
    "endpoint": "https://webhooks.acmesaude.com.br/nilo/fhir"
  ]
] as [String : Any]

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

let request = NSMutableURLRequest(url: NSURL(string: "https://landing-zone-api.nilo.services/fhir/resources/Subscription")! 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()
```

### Response (200)

```json
{
  "resourceType": "Subscription",
  "status": "requested",
  "criteria": "Patient",
  "reason": "Sincronizar cadastro de pacientes",
  "channel": {
    "type": "rest-hook",
    "endpoint": "https://webhooks.acmesaude.com.br/nilo/fhir",
    "header": [
      "secret: 8f14e45fceea167a5a36dedd4bea2543"
    ]
  },
  "id": "db1704e5-8c93-4a26-b0f7-45e28a1c9b60",
  "meta": {
    "versionId": "MTc4NjAyMTQ1MjkwNTAwMDM2Nw",
    "lastUpdated": "2026-08-11T12:20:03.771000Z",
    "tag": [
      {
        "code": "412",
        "system": "https://landing-zone-api.nilo.services/fhir/resources/NamingSystem/landing-zone-api--fhir-webhook"
      }
    ]
  }
}
```

| Campo              | Obrigatório | O que significa                                                       |
| ------------------ | ----------- | --------------------------------------------------------------------- |
| `resourceType`     | **sim**     | Constante `Subscription`                                              |
| `status`           | **sim**     | Na criação, tem de ser `requested`                                    |
| `reason`           | **sim**     | Exigido pelo FHIR. O texto é seu, e a plataforma não o usa para nada  |
| `criteria`         | **sim**     | O tipo de recurso a observar — opcionalmente com filtros, veja abaixo |
| `channel.type`     | **sim**     | Só `rest-hook`                                                        |
| `channel.endpoint` | **sim**     | A URL que a Nilo vai chamar                                           |
| `channel.header[]` | não         | Cabeçalhos extras, no formato `Nome: valor`                           |
| `contact[]`        | não         | E-mails avisados quando a assinatura é desativada. Só `system: email` |

> **Warning**
>
> **Uma assinatura viva por `criteria`.** Não dá para ter duas assinaturas ativas ou pendentes
> para o mesmo critério — e a comparação é da string inteira, filtros incluídos. Desligue a
> primeira antes de criar outra.

### `criteria` aceita filtros

Além do tipo de recurso, o `criteria` aceita parâmetros de busca depois de `?`, e só notifica o
que casar com eles:

```
Patient
Encounter?status=finished
Appointment?_include=Appointment:patient
```

> **Note**
>
> `_include` e `_revinclude` mudam o **formato** da notificação: em vez do recurso nu, você recebe
> um `Bundle` do tipo `searchset` com o recurso e os relacionados. Veja
> [O que chega no seu endpoint](#o-que-chega-no-seu-endpoint).

> **Note**
>
> Este recurso **não tem `identifier`** — o FHIR R4 não define o campo para ele. O identificador
> da assinatura vem em `meta.tag[0].code`, e é por ele que a Nilo a reencontra. Guarde-o se
> precisar correlacionar.

## O aperto de mão

Uma assinatura **não nasce ativa**. Depois de responder ao seu `POST`, a Nilo chama a sua URL
com uma requisição de verificação:

1. você cria a assinatura e recebe `status: requested`;
2. a Nilo faz um `POST` na sua URL com um `Bundle` do tipo `history`, contendo um
   `SubscriptionStatus` de `type: handshake`;
3. se a sua URL responder com sucesso (`2xx`), a assinatura passa a `active`;
4. se responder com erro, a assinatura passa a `error`, e o motivo fica no campo `error` do
   recurso.

> **Warning**
>
> **Enquanto a assinatura não estiver `active`, nenhuma notificação é entregue.**

> **Warning**
>
> **O aperto de mão pode chegar antes da resposta do `POST`.** Ele é disparado durante o
> processamento da criação, não depois dela — então o seu endpoint precisa estar de pé **antes**
> de você chamar a API, e não pode depender de nada que só exista depois da resposta.
>
> E não espere ver `status: active` na resposta da criação: ela devolve `requested`.

## O que chega no seu endpoint

A notificação é um `POST` no seu `endpoint`, com o **recurso que mudou** no corpo:

| Situação                                   | Corpo da notificação                                             |
| ------------------------------------------ | ---------------------------------------------------------------- |
| `criteria` simples                         | O recurso, nu                                                    |
| `criteria` com `_include` ou `_revinclude` | Um `Bundle` do tipo `searchset`, com o recurso e os relacionados |
| Recurso **excluído**                       | O recurso, com um `meta.tag` de `code: DELETE`                   |

> **Warning**
>
> **A exclusão é notificada com o recurso que deixou de existir**, marcado por `meta.tag[].code`
> igual a `DELETE`. Trate esse caso separadamente: o corpo parece uma atualização normal.
>
> E nela os filtros do `criteria` **quase não são avaliados**: como o recurso já não existe, só
> `active`, `status` e o modificador `:missing` são aplicados. Um filtro mais complexo não é
> considerado, e a notificação de exclusão chega mesmo assim.

> **Note**
>
> Eventos de `Bundle` só geram notificação quando o `Bundle` é do tipo `document`. Uma
> [carga em lote](/guia/operacoes/carga-em-lote) não dispara webhook — o que dispara são as
> escritas que ela faz.

## Como conferir que a chamada veio da Nilo

Toda entrega leva uma **assinatura HMAC** do corpo da requisição:

| Cabeçalho         | Conteúdo                                                            |
| ----------------- | ------------------------------------------------------------------- |
| `Content-Type`    | `application/fhir+json`                                             |
| `X-Hub-Signature` | `sha256=<hmac>` — HMAC-SHA256 do corpo, com o segredo da assinatura |

> **Warning**
>
> **Confira a assinatura em toda entrega.** Calcule o HMAC-SHA256 do corpo **cru** da requisição
> com o seu segredo e compare com o valor depois de `sha256=`. Uma chamada sem assinatura válida
> não veio da Nilo.

### O segredo

Você define o segredo mandando um cabeçalho chamado `secret` no `channel.header[]`:

### Request

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

**`Criar com segredo próprio e contato`**

```curl Criar com segredo próprio e contato
curl -X POST https://landing-zone-api.nilo.services/fhir/resources/Subscription \
     -H "x-api-key: <apiKey>" \
     -H "Content-Type: application/json" \
     -d '{
  "resourceType": "Subscription",
  "status": "requested",
  "criteria": "Encounter",
  "reason": "Sincronizar atendimentos",
  "channel": {
    "type": "rest-hook",
    "endpoint": "https://webhooks.acmesaude.com.br/nilo/fhir",
    "header": [
      "secret: 8f14e45fceea167a5a36dedd4bea2543",
      "X-Origem: nilo"
    ]
  },
  "contact": [
    {
      "system": "email",
      "value": "integracao@acmesaude.com.br"
    }
  ]
}'
```

**`Criar com segredo próprio e contato`**

```python Criar com segredo próprio e contato
import requests

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

payload = {
    "resourceType": "Subscription",
    "status": "requested",
    "criteria": "Encounter",
    "reason": "Sincronizar atendimentos",
    "channel": {
        "type": "rest-hook",
        "endpoint": "https://webhooks.acmesaude.com.br/nilo/fhir",
        "header": ["secret: 8f14e45fceea167a5a36dedd4bea2543", "X-Origem: nilo"]
    },
    "contact": [
        {
            "system": "email",
            "value": "integracao@acmesaude.com.br"
        }
    ]
}
headers = {
    "x-api-key": "<apiKey>",
    "Content-Type": "application/json"
}

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

print(response.json())
```

**`Criar com segredo próprio e contato`**

```javascript Criar com segredo próprio e contato
const url = 'https://landing-zone-api.nilo.services/fhir/resources/Subscription';
const options = {
  method: 'POST',
  headers: {'x-api-key': '<apiKey>', 'Content-Type': 'application/json'},
  body: '{"resourceType":"Subscription","status":"requested","criteria":"Encounter","reason":"Sincronizar atendimentos","channel":{"type":"rest-hook","endpoint":"https://webhooks.acmesaude.com.br/nilo/fhir","header":["secret: 8f14e45fceea167a5a36dedd4bea2543","X-Origem: nilo"]},"contact":[{"system":"email","value":"integracao@acmesaude.com.br"}]}'
};

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

**`Criar com segredo próprio e contato`**

```go Criar com segredo próprio e contato
package main

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

func main() {

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

	payload := strings.NewReader("{\n  \"resourceType\": \"Subscription\",\n  \"status\": \"requested\",\n  \"criteria\": \"Encounter\",\n  \"reason\": \"Sincronizar atendimentos\",\n  \"channel\": {\n    \"type\": \"rest-hook\",\n    \"endpoint\": \"https://webhooks.acmesaude.com.br/nilo/fhir\",\n    \"header\": [\n      \"secret: 8f14e45fceea167a5a36dedd4bea2543\",\n      \"X-Origem: nilo\"\n    ]\n  },\n  \"contact\": [\n    {\n      \"system\": \"email\",\n      \"value\": \"integracao@acmesaude.com.br\"\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))

}
```

**`Criar com segredo próprio e contato`**

```ruby Criar com segredo próprio e contato
require 'uri'
require 'net/http'

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

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\": \"Subscription\",\n  \"status\": \"requested\",\n  \"criteria\": \"Encounter\",\n  \"reason\": \"Sincronizar atendimentos\",\n  \"channel\": {\n    \"type\": \"rest-hook\",\n    \"endpoint\": \"https://webhooks.acmesaude.com.br/nilo/fhir\",\n    \"header\": [\n      \"secret: 8f14e45fceea167a5a36dedd4bea2543\",\n      \"X-Origem: nilo\"\n    ]\n  },\n  \"contact\": [\n    {\n      \"system\": \"email\",\n      \"value\": \"integracao@acmesaude.com.br\"\n    }\n  ]\n}"

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

**`Criar com segredo próprio e contato`**

```java Criar com segredo próprio e contato
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/Subscription")
  .header("x-api-key", "<apiKey>")
  .header("Content-Type", "application/json")
  .body("{\n  \"resourceType\": \"Subscription\",\n  \"status\": \"requested\",\n  \"criteria\": \"Encounter\",\n  \"reason\": \"Sincronizar atendimentos\",\n  \"channel\": {\n    \"type\": \"rest-hook\",\n    \"endpoint\": \"https://webhooks.acmesaude.com.br/nilo/fhir\",\n    \"header\": [\n      \"secret: 8f14e45fceea167a5a36dedd4bea2543\",\n      \"X-Origem: nilo\"\n    ]\n  },\n  \"contact\": [\n    {\n      \"system\": \"email\",\n      \"value\": \"integracao@acmesaude.com.br\"\n    }\n  ]\n}")
  .asString();
```

**`Criar com segredo próprio e contato`**

```php Criar com segredo próprio e contato
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://landing-zone-api.nilo.services/fhir/resources/Subscription', [
  'body' => '{
  "resourceType": "Subscription",
  "status": "requested",
  "criteria": "Encounter",
  "reason": "Sincronizar atendimentos",
  "channel": {
    "type": "rest-hook",
    "endpoint": "https://webhooks.acmesaude.com.br/nilo/fhir",
    "header": [
      "secret: 8f14e45fceea167a5a36dedd4bea2543",
      "X-Origem: nilo"
    ]
  },
  "contact": [
    {
      "system": "email",
      "value": "integracao@acmesaude.com.br"
    }
  ]
}',
  'headers' => [
    'Content-Type' => 'application/json',
    'x-api-key' => '<apiKey>',
  ],
]);

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

**`Criar com segredo próprio e contato`**

```csharp Criar com segredo próprio e contato
using RestSharp;

var client = new RestClient("https://landing-zone-api.nilo.services/fhir/resources/Subscription");
var request = new RestRequest(Method.POST);
request.AddHeader("x-api-key", "<apiKey>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"resourceType\": \"Subscription\",\n  \"status\": \"requested\",\n  \"criteria\": \"Encounter\",\n  \"reason\": \"Sincronizar atendimentos\",\n  \"channel\": {\n    \"type\": \"rest-hook\",\n    \"endpoint\": \"https://webhooks.acmesaude.com.br/nilo/fhir\",\n    \"header\": [\n      \"secret: 8f14e45fceea167a5a36dedd4bea2543\",\n      \"X-Origem: nilo\"\n    ]\n  },\n  \"contact\": [\n    {\n      \"system\": \"email\",\n      \"value\": \"integracao@acmesaude.com.br\"\n    }\n  ]\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

**`Criar com segredo próprio e contato`**

```swift Criar com segredo próprio e contato
import Foundation

let headers = [
  "x-api-key": "<apiKey>",
  "Content-Type": "application/json"
]
let parameters = [
  "resourceType": "Subscription",
  "status": "requested",
  "criteria": "Encounter",
  "reason": "Sincronizar atendimentos",
  "channel": [
    "type": "rest-hook",
    "endpoint": "https://webhooks.acmesaude.com.br/nilo/fhir",
    "header": ["secret: 8f14e45fceea167a5a36dedd4bea2543", "X-Origem: nilo"]
  ],
  "contact": [
    [
      "system": "email",
      "value": "integracao@acmesaude.com.br"
    ]
  ]
] as [String : Any]

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

let request = NSMutableURLRequest(url: NSURL(string: "https://landing-zone-api.nilo.services/fhir/resources/Subscription")! 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()
```

> **Warning**
>
> **Mande sempre o seu.** Não recebendo um cabeçalho `secret`, a Nilo gera um internamente — e
> esse valor gerado **não volta na resposta nem nas leituras**. Você fica com um webhook cuja
> assinatura não consegue conferir.
>
> O segredo que você mandar, esse, fica visível nas leituras seguintes da assinatura: trate a
> leitura de `Subscription` como dado sensível.

> **Note**
>
> Os demais cabeçalhos que você mandar em `channel.header[]` são **repassados em toda entrega**,
> junto com os dois acima. É por aí que se manda um token estático, se o seu endpoint exigir um —
> inclusive o próprio `secret`, que também vai repassado.
>
> Prefira validar pelo `X-Hub-Signature`, não pelo cabeçalho `secret`: o primeiro prova que o
> corpo não foi alterado; o segundo é só um valor fixo.

> **Warning**
>
> Um cabeçalho customizado com o nome `Content-Type` ou `X-Hub-Signature` **sobrescreve o da
> Nilo**, em silêncio — e aí a sua própria verificação de assinatura quebra. Não use esses dois
> nomes.

> **Note**
>
> Se o seu ambiente estiver configurado para isso, a Nilo obtém um token OAuth2 e o envia em
> `Authorization`, **substituindo** o que você tiver posto nesse cabeçalho. A configuração vale
> também para o aperto de mão, então o seu endpoint de token precisa estar de pé antes de você
> criar a assinatura. Fale com o **Suporte**.

## O que a Nilo espera do seu endpoint

> **Warning**
>
> **Responda rápido.** A entrega tem tempo limite: 5 segundos para conectar e 15 para a resposta.
> Um endpoint lento é tratado como falha.
>
> Responda `2xx` assim que receber, e processe depois. Não faça trabalho pesado dentro da
> requisição.

## Entrega, retentativa e desativação

A Nilo espera **`2xx`**. O que acontece quando não recebe:

| Resposta do seu endpoint               | O que a Nilo faz                                          |
| -------------------------------------- | --------------------------------------------------------- |
| `2xx`                                  | Entregue                                                  |
| Falha de rede, timeout, `5xx` ou `429` | **Reprocessa** automaticamente, por algumas tentativas    |
| `4xx`, exceto `429`                    | Falha **permanente** daquele evento — ele não é reenviado |

> **Warning**
>
> **A partir da terceira tentativa sem sucesso, a assinatura é desativada.** Ela passa a
> `status: error`, o motivo fica no campo `error` do recurso, e um alerta é enviado aos e-mails de
> `contact` — com o `criteria`, o endpoint, o status HTTP, a mensagem de erro e o link para o
> recurso que não pôde ser entregue.

### Reativação automática

> **Note**
>
> **Uma assinatura em `error` não precisa ser recriada.** No próximo evento daquele tipo de
> recurso, a Nilo reenvia o aperto de mão sozinha; respondendo `2xx`, a assinatura volta a
> `active` e o evento é entregue normalmente.
>
> O que ela **não** faz é reenviar os eventos ocorridos enquanto estava em `error`. Para não
> perder dados, reconcilie o período com um `GET` do recurso correspondente, filtrando por
> `_lastUpdated`.

## Desligar uma assinatura

### Request

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

**`Desligar uma assinatura`**

```curl Desligar uma assinatura
curl -X POST https://landing-zone-api.nilo.services/fhir/resources/Subscription \
     -H "x-api-key: <apiKey>" \
     -H "Content-Type: application/json" \
     -d '{
  "resourceType": "Subscription",
  "status": "off",
  "criteria": "Patient",
  "reason": "Encerrando a integração de pacientes",
  "channel": {
    "type": "rest-hook",
    "endpoint": "https://webhooks.acmesaude.com.br/nilo/fhir"
  }
}'
```

**`Desligar uma assinatura`**

```python Desligar uma assinatura
import requests

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

payload = {
    "resourceType": "Subscription",
    "status": "off",
    "criteria": "Patient",
    "reason": "Encerrando a integração de pacientes",
    "channel": {
        "type": "rest-hook",
        "endpoint": "https://webhooks.acmesaude.com.br/nilo/fhir"
    }
}
headers = {
    "x-api-key": "<apiKey>",
    "Content-Type": "application/json"
}

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

print(response.json())
```

**`Desligar uma assinatura`**

```javascript Desligar uma assinatura
const url = 'https://landing-zone-api.nilo.services/fhir/resources/Subscription';
const options = {
  method: 'POST',
  headers: {'x-api-key': '<apiKey>', 'Content-Type': 'application/json'},
  body: '{"resourceType":"Subscription","status":"off","criteria":"Patient","reason":"Encerrando a integração de pacientes","channel":{"type":"rest-hook","endpoint":"https://webhooks.acmesaude.com.br/nilo/fhir"}}'
};

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

**`Desligar uma assinatura`**

```go Desligar uma assinatura
package main

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

func main() {

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

	payload := strings.NewReader("{\n  \"resourceType\": \"Subscription\",\n  \"status\": \"off\",\n  \"criteria\": \"Patient\",\n  \"reason\": \"Encerrando a integração de pacientes\",\n  \"channel\": {\n    \"type\": \"rest-hook\",\n    \"endpoint\": \"https://webhooks.acmesaude.com.br/nilo/fhir\"\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))

}
```

**`Desligar uma assinatura`**

```ruby Desligar uma assinatura
require 'uri'
require 'net/http'

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

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\": \"Subscription\",\n  \"status\": \"off\",\n  \"criteria\": \"Patient\",\n  \"reason\": \"Encerrando a integração de pacientes\",\n  \"channel\": {\n    \"type\": \"rest-hook\",\n    \"endpoint\": \"https://webhooks.acmesaude.com.br/nilo/fhir\"\n  }\n}"

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

**`Desligar uma assinatura`**

```java Desligar uma assinatura
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/Subscription")
  .header("x-api-key", "<apiKey>")
  .header("Content-Type", "application/json")
  .body("{\n  \"resourceType\": \"Subscription\",\n  \"status\": \"off\",\n  \"criteria\": \"Patient\",\n  \"reason\": \"Encerrando a integração de pacientes\",\n  \"channel\": {\n    \"type\": \"rest-hook\",\n    \"endpoint\": \"https://webhooks.acmesaude.com.br/nilo/fhir\"\n  }\n}")
  .asString();
```

**`Desligar uma assinatura`**

```php Desligar uma assinatura
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://landing-zone-api.nilo.services/fhir/resources/Subscription', [
  'body' => '{
  "resourceType": "Subscription",
  "status": "off",
  "criteria": "Patient",
  "reason": "Encerrando a integração de pacientes",
  "channel": {
    "type": "rest-hook",
    "endpoint": "https://webhooks.acmesaude.com.br/nilo/fhir"
  }
}',
  'headers' => [
    'Content-Type' => 'application/json',
    'x-api-key' => '<apiKey>',
  ],
]);

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

**`Desligar uma assinatura`**

```csharp Desligar uma assinatura
using RestSharp;

var client = new RestClient("https://landing-zone-api.nilo.services/fhir/resources/Subscription");
var request = new RestRequest(Method.POST);
request.AddHeader("x-api-key", "<apiKey>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"resourceType\": \"Subscription\",\n  \"status\": \"off\",\n  \"criteria\": \"Patient\",\n  \"reason\": \"Encerrando a integração de pacientes\",\n  \"channel\": {\n    \"type\": \"rest-hook\",\n    \"endpoint\": \"https://webhooks.acmesaude.com.br/nilo/fhir\"\n  }\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

**`Desligar uma assinatura`**

```swift Desligar uma assinatura
import Foundation

let headers = [
  "x-api-key": "<apiKey>",
  "Content-Type": "application/json"
]
let parameters = [
  "resourceType": "Subscription",
  "status": "off",
  "criteria": "Patient",
  "reason": "Encerrando a integração de pacientes",
  "channel": [
    "type": "rest-hook",
    "endpoint": "https://webhooks.acmesaude.com.br/nilo/fhir"
  ]
] as [String : Any]

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

let request = NSMutableURLRequest(url: NSURL(string: "https://landing-zone-api.nilo.services/fhir/resources/Subscription")! 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()
```

Mande `status: off` com o mesmo `criteria`. A assinatura ativa ou pendente daquele recurso é
encerrada, e o `end` do recurso passa a trazer o instante do desligamento.

> **Warning**
>
> Não havendo assinatura ativa nem pendente para aquele `criteria`, a chamada é recusada com
> `Not found webhook active or requested for criteria=…`.

## Consultar assinaturas

### Request

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

**`Busca com resultados`**

```curl Busca com resultados
curl https://landing-zone-api.nilo.services/fhir/resources/Subscription \
     -H "x-api-key: <apiKey>"
```

**`Busca com resultados`**

```python Busca com resultados
import requests

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

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

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

print(response.json())
```

**`Busca com resultados`**

```javascript Busca com resultados
const url = 'https://landing-zone-api.nilo.services/fhir/resources/Subscription';
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/Subscription"

	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/Subscription")

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/Subscription")
  .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/Subscription', [
  '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/Subscription");
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/Subscription")! 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()
```

### Response (200)

```json
{
  "resourceType": "Bundle",
  "type": "searchset",
  "entry": [
    {
      "fullUrl": "https://landing-zone-api.nilo.services/fhir/resources/Subscription/db1704e5-8c93-4a26-b0f7-45e28a1c9b60",
      "resource": {
        "resourceType": "Subscription",
        "status": "active",
        "criteria": "Patient",
        "reason": "-",
        "channel": {
          "type": "rest-hook",
          "endpoint": "https://webhooks.acmesaude.com.br/nilo/fhir",
          "header": [
            "secret: 8f14e45fceea167a5a36dedd4bea2543"
          ]
        },
        "id": "db1704e5-8c93-4a26-b0f7-45e28a1c9b60",
        "meta": {
          "versionId": "MTc4NjAyMTQ1MjkwNTAwMDM2Nw",
          "lastUpdated": "2026-08-11T12:20:03.771000Z",
          "tag": [
            {
              "code": "412",
              "system": "https://landing-zone-api.nilo.services/fhir/resources/NamingSystem/landing-zone-api--fhir-webhook"
            }
          ]
        }
      },
      "search": {
        "mode": "match"
      }
    }
  ],
  "link": []
}
```

### Filtrar a busca

| Parâmetro  | Filtra por                                                                                               | Modificadores                                                                                                           |
| ---------- | -------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
| `criteria` | O critério observado. Sem modificador, casa o que **começa** com o valor, ignorando maiúsculas e acentos | `:contains` casa o valor em **qualquer posição**; `:exact` casa só o valor **idêntico**, maiúsculas e acentos incluídos |
| `status`   | O estado da assinatura: `requested`, `active`, `error` ou `off`                                          | nenhum                                                                                                                  |
| `url`      | A URL de destino, comparada por igualdade                                                                | `:below` devolve as URLs que **começam** pelo valor; `:above` devolve as URLs que são **prefixo** do valor              |
| `_tag`     | A etiqueta que veio em `meta.tag[0]`, e é o caminho para uma assinatura específica                       | nenhum                                                                                                                  |

Para ver o que está entregando de fato:

### Request

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

**`Filtrar por status`**

```curl Filtrar por status
curl -G https://landing-zone-api.nilo.services/fhir/resources/Subscription \
     -H "x-api-key: <apiKey>" \
     -d status=active
```

**`Filtrar por status`**

```python Filtrar por status
import requests

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

querystring = {"status":"active"}

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

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

print(response.json())
```

**`Filtrar por status`**

```javascript Filtrar por status
const url = 'https://landing-zone-api.nilo.services/fhir/resources/Subscription?status=active';
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);
}
```

**`Filtrar por status`**

```go Filtrar por status
package main

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

func main() {

	url := "https://landing-zone-api.nilo.services/fhir/resources/Subscription?status=active"

	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))

}
```

**`Filtrar por status`**

```ruby Filtrar por status
require 'uri'
require 'net/http'

url = URI("https://landing-zone-api.nilo.services/fhir/resources/Subscription?status=active")

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
```

**`Filtrar por status`**

```java Filtrar por status
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/Subscription?status=active")
  .header("x-api-key", "<apiKey>")
  .asString();
```

**`Filtrar por status`**

```php Filtrar por status
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

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

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

**`Filtrar por status`**

```csharp Filtrar por status
using RestSharp;

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

**`Filtrar por status`**

```swift Filtrar por status
import Foundation

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

let request = NSMutableURLRequest(url: NSURL(string: "https://landing-zone-api.nilo.services/fhir/resources/Subscription?status=active")! 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()
```

Mais de um estado numa busca só — separados por vírgula, ou repetindo o parâmetro, tanto faz:

```
?status=active,error
?status=active&status=error
```

> **Note**
>
> As duas formas devolvem as assinaturas que estejam em **qualquer um** dos estados pedidos. É
> uma exceção à regra do FHIR, em que repetir o parâmetro significa E: como a assinatura tem um
> estado só, exigir dois ao mesmo tempo não devolveria nada.
>
> Um `status` vazio não filtra nada, e a busca volta completa.

> **Warning**
>
> **`status` não aceita modificador.** O estado real não vive no armazenamento — a Nilo o resolve
> antes de buscar. Com modificador — `status:not`, `status:missing` — o filtro escapa dessa
> tradução e é repassado direto, e o armazenamento tem toda assinatura gravada como `off`: a
> resposta não terá relação com o estado real. Liste os estados que você quer, sem modificador.

### Buscar por um trecho do critério

O `criteria` é gravado como você o mandou, filtros incluídos, e sem modificador a busca casa só
o que **começa** com o valor. Para achar um trecho no meio da string, use `:contains`:

### Request

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

**`Filtrar por criteria`**

```curl Filtrar por criteria
curl -G https://landing-zone-api.nilo.services/fhir/resources/Subscription \
     -H "x-api-key: <apiKey>" \
     -d criteria:contains=Patient
```

**`Filtrar por criteria`**

```python Filtrar por criteria
import requests

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

querystring = {"criteria:contains":"Patient"}

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

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

print(response.json())
```

**`Filtrar por criteria`**

```javascript Filtrar por criteria
const url = 'https://landing-zone-api.nilo.services/fhir/resources/Subscription?criteria%3Acontains=Patient';
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);
}
```

**`Filtrar por criteria`**

```go Filtrar por criteria
package main

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

func main() {

	url := "https://landing-zone-api.nilo.services/fhir/resources/Subscription?criteria%3Acontains=Patient"

	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))

}
```

**`Filtrar por criteria`**

```ruby Filtrar por criteria
require 'uri'
require 'net/http'

url = URI("https://landing-zone-api.nilo.services/fhir/resources/Subscription?criteria%3Acontains=Patient")

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
```

**`Filtrar por criteria`**

```java Filtrar por criteria
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/Subscription?criteria%3Acontains=Patient")
  .header("x-api-key", "<apiKey>")
  .asString();
```

**`Filtrar por criteria`**

```php Filtrar por criteria
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('GET', 'https://landing-zone-api.nilo.services/fhir/resources/Subscription?criteria%3Acontains=Patient', [
  'headers' => [
    'x-api-key' => '<apiKey>',
  ],
]);

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

**`Filtrar por criteria`**

```csharp Filtrar por criteria
using RestSharp;

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

**`Filtrar por criteria`**

```swift Filtrar por criteria
import Foundation

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

let request = NSMutableURLRequest(url: NSURL(string: "https://landing-zone-api.nilo.services/fhir/resources/Subscription?criteria%3Acontains=Patient")! 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()
```

### Response (200)

```json
{
  "resourceType": "Bundle",
  "type": "searchset",
  "entry": [
    {
      "fullUrl": "https://landing-zone-api.nilo.services/fhir/resources/Subscription/db1704e5-8c93-4a26-b0f7-45e28a1c9b60",
      "resource": {
        "resourceType": "Subscription",
        "status": "active",
        "criteria": "Patient",
        "reason": "-",
        "channel": {
          "type": "rest-hook",
          "endpoint": "https://webhooks.acmesaude.com.br/nilo/fhir"
        },
        "id": "db1704e5-8c93-4a26-b0f7-45e28a1c9b60",
        "meta": {
          "tag": [
            {
              "code": "412",
              "system": "https://landing-zone-api.nilo.services/fhir/resources/NamingSystem/landing-zone-api--fhir-webhook"
            }
          ]
        }
      },
      "search": {
        "mode": "match"
      }
    },
    {
      "fullUrl": "https://landing-zone-api.nilo.services/fhir/resources/Subscription/7c0a1b94-30f2-4c1b-9a1e-6f2d8b5c4e11",
      "resource": {
        "resourceType": "Subscription",
        "status": "off",
        "criteria": "Encounter?_include=Encounter:patient",
        "reason": "-",
        "channel": {
          "type": "rest-hook",
          "endpoint": "https://webhooks.acmesaude.com.br/nilo/fhir/encounter"
        },
        "id": "7c0a1b94-30f2-4c1b-9a1e-6f2d8b5c4e11",
        "meta": {
          "tag": [
            {
              "code": "418",
              "system": "https://landing-zone-api.nilo.services/fhir/resources/NamingSystem/landing-zone-api--fhir-webhook"
            }
          ]
        }
      },
      "search": {
        "mode": "match"
      }
    }
  ],
  "link": []
}
```

`Encounter?_include=Encounter:patient` também volta: `:contains` casa em qualquer posição, e
ignora maiúsculas e acentos. Com `criteria=Patient`, viria só a primeira.

### Combinar filtros

Os parâmetros se somam com E — a assinatura tem de casar com todos:

### Request

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

**`Combinar status e criteria`**

```curl Combinar status e criteria
curl -G https://landing-zone-api.nilo.services/fhir/resources/Subscription \
     -H "x-api-key: <apiKey>" \
     -d criteria:contains=Patient \
     -d status=active
```

**`Combinar status e criteria`**

```python Combinar status e criteria
import requests

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

querystring = {"criteria:contains":"Patient","status":"active"}

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

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

print(response.json())
```

**`Combinar status e criteria`**

```javascript Combinar status e criteria
const url = 'https://landing-zone-api.nilo.services/fhir/resources/Subscription?criteria%3Acontains=Patient&status=active';
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);
}
```

**`Combinar status e criteria`**

```go Combinar status e criteria
package main

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

func main() {

	url := "https://landing-zone-api.nilo.services/fhir/resources/Subscription?criteria%3Acontains=Patient&status=active"

	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))

}
```

**`Combinar status e criteria`**

```ruby Combinar status e criteria
require 'uri'
require 'net/http'

url = URI("https://landing-zone-api.nilo.services/fhir/resources/Subscription?criteria%3Acontains=Patient&status=active")

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
```

**`Combinar status e criteria`**

```java Combinar status e criteria
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/Subscription?criteria%3Acontains=Patient&status=active")
  .header("x-api-key", "<apiKey>")
  .asString();
```

**`Combinar status e criteria`**

```php Combinar status e criteria
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('GET', 'https://landing-zone-api.nilo.services/fhir/resources/Subscription?criteria%3Acontains=Patient&status=active', [
  'headers' => [
    'x-api-key' => '<apiKey>',
  ],
]);

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

**`Combinar status e criteria`**

```csharp Combinar status e criteria
using RestSharp;

var client = new RestClient("https://landing-zone-api.nilo.services/fhir/resources/Subscription?criteria%3Acontains=Patient&status=active");
var request = new RestRequest(Method.GET);
request.AddHeader("x-api-key", "<apiKey>");
IRestResponse response = client.Execute(request);
```

**`Combinar status e criteria`**

```swift Combinar status e criteria
import Foundation

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

let request = NSMutableURLRequest(url: NSURL(string: "https://landing-zone-api.nilo.services/fhir/resources/Subscription?criteria%3Acontains=Patient&status=active")! 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()
```

### Response (200)

```json
{
  "resourceType": "Bundle",
  "type": "searchset",
  "entry": [
    {
      "fullUrl": "https://landing-zone-api.nilo.services/fhir/resources/Subscription/db1704e5-8c93-4a26-b0f7-45e28a1c9b60",
      "resource": {
        "resourceType": "Subscription",
        "status": "active",
        "criteria": "Patient",
        "reason": "-",
        "channel": {
          "type": "rest-hook",
          "endpoint": "https://webhooks.acmesaude.com.br/nilo/fhir"
        },
        "id": "db1704e5-8c93-4a26-b0f7-45e28a1c9b60",
        "meta": {
          "tag": [
            {
              "code": "412",
              "system": "https://landing-zone-api.nilo.services/fhir/resources/NamingSystem/landing-zone-api--fhir-webhook"
            }
          ]
        }
      },
      "search": {
        "mode": "match"
      }
    }
  ],
  "link": []
}
```

Para reencontrar uma assinatura específica, use o `_tag` que veio em `meta.tag[0]`:

```bash
curl --request GET \
  --url 'https://landing-zone-api.nilo.services/fhir/resources/Subscription?_tag=https://landing-zone-api.nilo.services/fhir/resources/NamingSystem/landing-zone-api--fhir-webhook|412' \
  --header 'x-api-key: SUA_API_KEY'
```

| `status`    | O que significa                                                                                                                                     |
| ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| `requested` | Criada, aguardando o aperto de mão. Ainda não recebe notificações                                                                                   |
| `active`    | Aperto de mão respondido — entregando                                                                                                               |
| `error`     | Desativada por falhas de entrega, ou por aperto de mão que falhou. O motivo está em `error`, e ela é **reativada sozinha** quando o endpoint voltar |
| `off`       | Desligada manualmente. Só volta criando uma assinatura nova                                                                                         |

### Request

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

**`Assinatura encontrada`**

```curl Assinatura encontrada
curl https://landing-zone-api.nilo.services/fhir/resources/Subscription/id \
     -H "x-api-key: <apiKey>"
```

**`Assinatura encontrada`**

```python Assinatura encontrada
import requests

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

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

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

print(response.json())
```

**`Assinatura encontrada`**

```javascript Assinatura encontrada
const url = 'https://landing-zone-api.nilo.services/fhir/resources/Subscription/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);
}
```

**`Assinatura encontrada`**

```go Assinatura encontrada
package main

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

func main() {

	url := "https://landing-zone-api.nilo.services/fhir/resources/Subscription/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))

}
```

**`Assinatura encontrada`**

```ruby Assinatura encontrada
require 'uri'
require 'net/http'

url = URI("https://landing-zone-api.nilo.services/fhir/resources/Subscription/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
```

**`Assinatura encontrada`**

```java Assinatura encontrada
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/Subscription/id")
  .header("x-api-key", "<apiKey>")
  .asString();
```

**`Assinatura encontrada`**

```php Assinatura encontrada
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

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

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

**`Assinatura encontrada`**

```csharp Assinatura encontrada
using RestSharp;

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

**`Assinatura encontrada`**

```swift Assinatura encontrada
import Foundation

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

let request = NSMutableURLRequest(url: NSURL(string: "https://landing-zone-api.nilo.services/fhir/resources/Subscription/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`.

### Response (200)

```json
{
  "fullUrl": "https://landing-zone-api.nilo.services/fhir/resources/Subscription/db1704e5-8c93-4a26-b0f7-45e28a1c9b60",
  "resource": {
    "resourceType": "Subscription",
    "status": "active",
    "criteria": "Patient",
    "reason": "-",
    "channel": {
      "type": "rest-hook",
      "endpoint": "https://webhooks.acmesaude.com.br/nilo/fhir",
      "header": [
        "secret: 8f14e45fceea167a5a36dedd4bea2543"
      ]
    },
    "id": "db1704e5-8c93-4a26-b0f7-45e28a1c9b60",
    "meta": {
      "versionId": "MTc4NjAyMTQ1MjkwNTAwMDM2Nw",
      "lastUpdated": "2026-08-11T12:20:03.771000Z",
      "tag": [
        {
          "code": "412",
          "system": "https://landing-zone-api.nilo.services/fhir/resources/NamingSystem/landing-zone-api--fhir-webhook"
        }
      ]
    }
  },
  "search": {
    "mode": "match"
  }
}
```

## Erros

Recusa é `400`. Neste recurso o `issue[].code` é sempre `exception`, **sem `expression`**, e o
`details.text` vem embrulhado — algo como
`ValidationError: ['Only channel=rest-hook subscriptions are supported']`.

**Não compare o texto por igualdade**: procure a mensagem como substring, ou simplesmente trate
`400` como "assinatura recusada".

| Mensagem, dentro do texto                              | Quando                                           |
| ------------------------------------------------------ | ------------------------------------------------ |
| `Only channel=rest-hook subscriptions are supported`   | `channel.type` diferente de `rest-hook`          |
| `Subscriptions must start with status=requested`       | Criação com `status` diferente de `requested`    |
| `criteria=… is not a valid FHIR resource`              | O `criteria` não é um tipo de recurso do FHIR    |
| `Only contact system=email are supported. …`           | Um `contact` com `system` diferente de `email`   |
| `The contact email "…" is invalid.`                    | O e-mail do contato não é válido                 |
| `Not found webhook active or requested for criteria=…` | `status: off` sem assinatura correspondente      |
| mensagem de constraint da plataforma                   | Já existe assinatura viva para aquele `criteria` |

### Response (200)

```json
{
  "resourceType": "Subscription",
  "status": "requested",
  "criteria": "Patient",
  "reason": "Sincronizar cadastro de pacientes",
  "channel": {
    "type": "rest-hook",
    "endpoint": "https://webhooks.acmesaude.com.br/nilo/fhir",
    "header": [
      "secret: 8f14e45fceea167a5a36dedd4bea2543"
    ]
  },
  "id": "db1704e5-8c93-4a26-b0f7-45e28a1c9b60",
  "meta": {
    "versionId": "MTc4NjAyMTQ1MjkwNTAwMDM2Nw",
    "lastUpdated": "2026-08-11T12:20:03.771000Z",
    "tag": [
      {
        "code": "412",
        "system": "https://landing-zone-api.nilo.services/fhir/resources/NamingSystem/landing-zone-api--fhir-webhook"
      }
    ]
  }
}
```

## Trocar o endpoint ou o critério

Não há atualização: desligue a assinatura e crie outra. Para não ficar sem cobertura entre as
duas chamadas, faça as duas numa [carga em lote](/guia/operacoes/carga-em-lote), com a entrada
de `status: off` **primeiro** — as entradas são processadas na ordem do array.

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

* canais que não sejam `rest-hook`;
* **alterar** uma assinatura: desligue e crie outra;
* **reenvio** dos eventos ocorridos enquanto a assinatura esteve em `error` ou `off`;
* um `identifier` próprio: a assinatura é identificada por `meta.tag`.