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

# Abrir um atendimento

> Da elegibilidade ao acompanhamento, sem consultar outra fonte.

Este guia cobre o fluxo completo de abrir um atendimento pela API pública: verificar elegibilidade,
criar o atendimento, e acompanhar seu andamento. Todos os exemplos assumem um token já obtido — veja
[Primeiros passos](https://docs-koolisys.eixoassistencia.com.br/primeiros-passos.md) se ainda não tiver um.

## 1. Consulte a elegibilidade

Antes de abrir um atendimento, verifique se o cliente e o veículo têm cobertura ativa para o
serviço desejado. Este passo é só leitura e nunca consome cota de uso — consultar elegibilidade
antes evita metade dos erros de criação.

```bash cURL theme={null}
curl "https://api-koolisys.eixoassistencia.com.br/v1/eligibility?document=12345678900&plate=ABC1D23" \
  --header "Authorization: Bearer <token>"
```

```js Node (fetch nativo) theme={null}
const params = new URLSearchParams({ document: "12345678900", plate: "ABC1D23" });

const response = await fetch(
  `https://api-koolisys.eixoassistencia.com.br/v1/eligibility?${params}`,
  {
    headers: { Authorization: "Bearer <token>" },
  },
);

const body = await response.json();
console.log(body.data.covered);
```

Resposta quando há cobertura (`200`):

```json theme={null}
{
  "data": {
    "covered": true,
    "plan": {
      "id": 42,
      "name": "Plano Proteção Total",
      "contractCode": null
    },
    "limits": {
      "usages": { "limit": 5, "used": 1, "remaining": 4 },
      "kmPerUse": 100,
      "valuePerUseCents": null
    },
    "coveredServices": [
      {
        "id": 1,
        "name": "Guincho",
        "category": null,
        "monthlyLimit": null,
        "valueLimitCents": null
      }
    ],
    "customerPaysExcess": false
  },
  "meta": {},
  "errors": []
}
```

Quando não há cobertura, `covered` vem `false` e `plan`/`limits` vêm `null` — não é um erro, é uma
resposta `200` normal. Trate `covered: false` na sua aplicação antes de tentar abrir o atendimento:
uma tentativa de criação sem cobertura devolve `422 NOT_COVERED` (ver [Erros e
limites](https://docs-koolisys.eixoassistencia.com.br/erros-e-limites.md)).

O documento nunca é registrado em log pela Koolisys — ele só existe na sua requisição.

## 2. Abra o atendimento

`POST /v1/attendances` abre o atendimento aguardando a central escolher o prestador — esta chamada
**nunca aciona** um prestador automaticamente. Ela exige o cabeçalho `Idempotency-Key` (veja
[Idempotência](https://docs-koolisys.eixoassistencia.com.br/idempotencia.md)):

```bash cURL theme={null}
curl --request POST https://api-koolisys.eixoassistencia.com.br/v1/attendances \
  --header "Authorization: Bearer <token>" \
  --header "Content-Type: application/json" \
  --header "Idempotency-Key: 6f1c2e3a-9b4d-4a1e-8c3f-2d1e0a9b8c7d" \
  --data '{
    "attendanceTypeId": 7,
    "serviceId": 7,
    "attendanceTypeDetail": "Pane seca no estacionamento",
    "customerDocument": "12345678900",
    "vehiclePlate": "ABC1D23",
    "origin": {
      "addressLine": "Av. Paulista, 1000",
      "number": "1000",
      "complement": "Sala 12",
      "district": "Bela Vista",
      "city": "São Paulo",
      "state": "SP",
      "zipCode": "01310-100",
      "latitude": -23.561414,
      "longitude": -46.655881,
      "reference": "Em frente ao metrô Trianon-MASP"
    },
    "notes": "Cliente aguarda no local, veículo não sai do lugar."
  }'
```

```js Node (fetch nativo) theme={null}
const response = await fetch("https://api-koolisys.eixoassistencia.com.br/v1/attendances", {
  method: "POST",
  headers: {
    Authorization: "Bearer <token>",
    "Content-Type": "application/json",
    "Idempotency-Key": crypto.randomUUID(),
  },
  body: JSON.stringify({
    attendanceTypeId: 7,
    serviceId: 7,
    attendanceTypeDetail: "Pane seca no estacionamento",
    customerDocument: "12345678900",
    vehiclePlate: "ABC1D23",
    origin: {
      addressLine: "Av. Paulista, 1000",
      number: "1000",
      complement: "Sala 12",
      district: "Bela Vista",
      city: "São Paulo",
      state: "SP",
      zipCode: "01310-100",
      latitude: -23.561414,
      longitude: -46.655881,
      reference: "Em frente ao metrô Trianon-MASP",
    },
    notes: "Cliente aguarda no local, veículo não sai do lugar.",
  }),
});

const body = await response.json();
console.log(body.data.id, body.data.status);
```

Resposta (`201` numa criação nova, `200` numa repetição idempotente — o corpo é o mesmo atendimento
nos dois casos):

```json theme={null}
{
  "data": {
    "id": 1024,
    "number": "AT-2026-000123",
    "status": "IN_PROGRESS",
    "customerDocument": "12345678900",
    "vehiclePlate": "ABC1D23",
    "attendanceTypeId": 7,
    "attendanceTypeDetail": "Pane seca no estacionamento",
    "notes": "Cliente aguarda no local, veículo não sai do lugar.",
    "milestones": {
      "openedAt": "2026-08-20T13:05:00.000Z",
      "providerDispatchedAt": "2026-08-20T13:10:00.000Z",
      "providerEnRouteAt": "2026-08-20T13:12:00.000Z",
      "providerArrivedAt": "2026-08-20T13:40:00.000Z",
      "serviceStartedAt": "2026-08-20T13:42:00.000Z",
      "concludedAt": null,
      "canceledAt": null
    },
    "createdAt": "2026-08-20T13:00:00.000Z",
    "location": {
      "addressLine": "Av. Paulista, 1000",
      "city": "São Paulo",
      "state": "SP",
      "latitude": -23.561414,
      "longitude": -46.655881
    },
    "provider": {
      "id": 3,
      "status": "ACCEPTED",
      "dispatchedAt": "2026-08-20T13:10:00.000Z",
      "etaAt": "2026-08-20T13:35:00.000Z"
    },
    "amountCents": 18500,
    "distanceKm": 12.4,
    "history": [
      {
        "type": "ATTENDANCE_OPENED",
        "summary": "Atendimento aberto pela API pública",
        "occurredAt": "2026-08-20T13:00:00.000Z"
      },
      {
        "type": "PROVIDER_DISPATCHED",
        "summary": "Prestador acionado",
        "occurredAt": "2026-08-20T13:10:00.000Z"
      }
    ]
  },
  "meta": {},
  "errors": []
}
```

`customerDocument` vem em claro na resposta. `attendanceTypeId` identifica o tipo de atendimento e
`serviceId` o serviço do catálogo — os dois são obrigatórios, e o serviço precisa pertencer ao tipo
escolhido. Consulte `GET /v1/attendance-types` para a lista de tipos ativos com a categoria e os
serviços que cada um agrupa (um mesmo serviço pode aparecer em mais de um tipo — ex.: Reboque leve
em "Colisão" e em "Pane mecânica"); os ids em `services` são os mesmos de `GET /v1/services`.
`attendanceTypeDetail` só é obrigatório quando o tipo exige justificativa.

`amountCents` (valor do acionamento mais recente, em centavos) e `distanceKm` (distância
percorrida) vêm nulos enquanto nenhum prestador foi acionado. Depois de acionado, refletem o
acionamento mais recente e nunca são recalculados — inclusive depois de `COMPLETED`, quando já
representam o valor final apurado. `distanceKm` também fica nulo quando o prestador é avulso (sem
rota calculada).

```bash theme={null}
curl https://api-koolisys.eixoassistencia.com.br/v1/attendance-types \
  --header "Authorization: Bearer <token>"
```

Enviar um `serviceId` que não pertence ao tipo devolve `400 VALIDATION_ERROR` com
`field: "attendanceTypeId"`.

### Serviços que exigem destino

Alguns serviços (ex.: reboque) exigem um `destination`, no mesmo formato de `origin`. Se o serviço
escolhido em `serviceId` exigir destino, envie o campo:

```json theme={null}
{
  "attendanceTypeId": 7,
  "serviceId": 7,
  "customerDocument": "12345678900",
  "vehiclePlate": "ABC1D23",
  "origin": {
    "addressLine": "Av. Paulista, 1000",
    "city": "São Paulo",
    "state": "SP",
    "latitude": -23.561414,
    "longitude": -46.655881
  },
  "destination": {
    "addressLine": "Rua Augusta, 500",
    "city": "São Paulo",
    "state": "SP",
    "latitude": -23.554944,
    "longitude": -46.661236
  }
}
```

Quem decide se `destination` é obrigatório é o serviço, nunca o integrador: enviar `destination`
para um serviço que não exige destino, ou deixar de enviá-lo para um que exige, devolve
`400 VALIDATION_ERROR` com `field: "destination"`:

```json theme={null}
{
  "data": null,
  "errors": [
    { "code": "VALIDATION_ERROR", "field": "destination", "message": "Este serviço exige destino" }
  ]
}
```

## 3. Acompanhe o atendimento

### Consultar um atendimento específico

```bash cURL theme={null}
curl https://api-koolisys.eixoassistencia.com.br/v1/attendances/1024 \
  --header "Authorization: Bearer <token>"
```

```js Node (fetch nativo) theme={null}
const id = 1024;
const response = await fetch(`https://api-koolisys.eixoassistencia.com.br/v1/attendances/${id}`, {
  headers: { Authorization: "Bearer <token>" },
});

const body = await response.json();
console.log(body.data.status, body.data.provider);
```

A resposta traz o mesmo formato do passo anterior, sempre com o estado mais atual — `status`,
`provider` (quando já há um prestador acionado) e `history`, a linha do tempo do atendimento.

Um atendimento de outra contratante devolve `404 NOT_FOUND`, exatamente como um atendimento
inexistente — nunca `403`, para não revelar que o id pertence a outra empresa.

### Listar atendimentos

```bash cURL theme={null}
curl "https://api-koolisys.eixoassistencia.com.br/v1/attendances?status=IN_PROGRESS&limit=20" \
  --header "Authorization: Bearer <token>"
```

```js Node (fetch nativo) theme={null}
const params = new URLSearchParams({ status: "IN_PROGRESS", limit: "20" });

const response = await fetch(
  `https://api-koolisys.eixoassistencia.com.br/v1/attendances?${params}`,
  {
    headers: { Authorization: "Bearer <token>" },
  },
);

const body = await response.json();
console.log(body.data.length, body.meta.nextCursor);
```

Resposta (`200`):

```json theme={null}
{
  "data": [
    {
      "id": 1024,
      "number": "AT-2026-000123",
      "status": "IN_PROGRESS",
      "customerDocument": "12345678900",
      "vehiclePlate": "ABC1D23",
      "attendanceTypeId": 7,
      "attendanceTypeDetail": "Pane seca no estacionamento",
      "notes": "Cliente aguarda no local, veículo não sai do lugar.",
      "milestones": {
        "openedAt": "2026-08-20T13:05:00.000Z",
        "providerDispatchedAt": "2026-08-20T13:10:00.000Z",
        "providerEnRouteAt": "2026-08-20T13:12:00.000Z",
        "providerArrivedAt": "2026-08-20T13:40:00.000Z",
        "serviceStartedAt": "2026-08-20T13:42:00.000Z",
        "concludedAt": null,
        "canceledAt": null
      },
      "createdAt": "2026-08-20T13:00:00.000Z",
      "amountCents": 18500,
      "distanceKm": 12.4
    }
  ],
  "meta": { "nextCursor": null },
  "errors": []
}
```

A listagem é paginada por cursor: quando `meta.nextCursor` não é `null`, use-o no parâmetro `cursor`
da próxima chamada para seguir para a página seguinte. Ela nunca inclui atendimentos em rascunho —
só os que já foram efetivamente abertos. Filtre por `status`, e por período de abertura com
`openedFrom`/`openedTo` (datas ISO 8601).

`amountCents` e `distanceKm` seguem a mesma regra da consulta individual (veja acima): refletem o
acionamento mais recente de cada atendimento da página, nulos enquanto nenhum prestador foi
acionado.

## Resumo do fluxo

1. `GET /v1/attendance-types` — resolva o par tipo de atendimento + serviço.
2. `GET /v1/eligibility` — confirme cobertura antes de criar.
3. `POST /v1/attendances` com `Idempotency-Key` — abra o atendimento.
4. `GET /v1/attendances/:id` ou `GET /v1/attendances` — acompanhe o andamento.

Nenhum desses passos aciona um prestador diretamente — a escolha do prestador continua manual, do
lado da central Koolisys.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.