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

# Trabalhos assíncronos

> Como funcionam as consultas de longa duração: esperar de forma síncrona, fazer polling ou receber um callback.

Algumas consultas do Croma demoram mais para responder, de alguns segundos
até alguns minutos. Elas são executadas como **trabalhos assíncronos**: a
mesma solicitação pode ser resolvida de três maneiras diferentes, e você escolhe
qual se ajusta à sua aplicação.

<Note>
  **Você não precisa fazer nada especial.** Por padrão esses endpoints se
  comportam como qualquer outro: você faz `POST` e recebe `{ "data": … }` de
  volta. As opções a seguir são opt-in, para quando você preferir não manter
  uma conexão aberta.
</Note>

## Quais endpoints são assíncronos?

Estas consultas são executadas como trabalhos assíncronos:

**Colômbia**

* [Consejo de Estado](/pt/guides/colombia/consejo-estado), busca de jurisprudência e uma providência
* [Policía Nacional](/pt/guides/colombia/policia), antecedentes criminais
* [ADRES](/pt/guides/colombia/adres), status de afiliação em saúde
* [SICAAC](/pt/guides/colombia/sicaac), casos de insolvência
* [Superfinanciera](/pt/guides/colombia/superfinanciera), reclamações
* [RUNT](/pt/guides/colombia/runt), veículo por placa e histórico do veículo por placa
* [SIMIT](/pt/guides/colombia/simit), situação da conta
* [Contaduría](/pt/guides/colombia/contaduria), devedores inadimplentes do Estado
* [DIAN](/pt/guides/colombia/dian), validação de documento eletrônico

**Peru**

* [SUNAT](/pt/guides/peru/sunat), todas as consultas (RUC, documento, nome, contribuintes)
* [RREE](/pt/guides/peru/rree), carteiras de estrangeiro
* [SAT Lima](/pt/guides/peru/sat-lima), situação da conta e [capturas](/pt/guides/peru/sat-lima-capturas)
* [Callao](/pt/guides/peru/callao-papeletas), papeletas
* [SUTRAN](/pt/guides/peru/sutran-infracciones), infrações
* [APESEG](/pt/guides/peru/apeseg-soat) e [SBS](/pt/guides/peru/sbs-soat), SOAT

**México**

* [SIEM](/pt/guides/mexico/siem), estabelecimentos comerciais

Todos os demais endpoints respondem de forma síncrona, sem nenhum trabalho
envolvido.

## As três maneiras de obter um resultado

| Modo                                   | O que você envia                    | O que você recebe                                                    |
| -------------------------------------- | ----------------------------------- | -------------------------------------------------------------------- |
| **Esperar de forma síncrona** (padrão) | nada adicional, ou `Prefer: wait=N` | `200 { data }` se terminar a tempo, caso contrário `202`             |
| **Polling**                            | `Prefer: wait=0`                    | `202` imediatamente, depois `GET /jobs/:id` até terminar             |
| **Callback**                           | `callback_url` no corpo             | `202` imediatamente, depois um `POST` para a sua URL quando terminar |

As três se apoiam no **mesmo trabalho**, então escolha conforme cada solicitação.

<Note>
  Se o Croma já tem um resultado recente para a mesma consulta, qualquer
  modo retorna `200 { data }` imediatamente (cabeçalho `X-Cache: HIT`) e
  nenhum trabalho é criado; no modo callback nenhum `POST` chega. Sempre
  trate um `200` direto.
</Note>

***

## Modo 1: Esperar de forma síncrona (padrão)

Simplesmente chame o endpoint. A solicitação fica aberta até o trabalho
terminar (até **55 segundos**) e retorna o resultado na forma habitual
`{ data }`, idêntica a um endpoint síncrono.

<CodeGroup>
  ```bash cURL theme={"dark"}
  curl https://api.croma.run/co/policia/criminal-records/v1 \
    -H "Authorization: Bearer $CROMA_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{ "document_number": "1234567890" }'
  ```

  ```ts TypeScript theme={"dark"}
  const res = await fetch(
    "https://api.croma.run/co/policia/criminal-records/v1",
    {
      method: "POST",
      headers: {
        Authorization: `Bearer ${process.env.CROMA_API_KEY}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({ document_number: "1234567890" }),
    },
  );

  if (res.status === 200) {
    const { data } = await res.json(); // listo, úsalo
  } else if (res.status === 202) {
    // no terminó a tiempo; haz polling al status_url (ver Modo 2)
  }
  ```
</CodeGroup>

Controle quanto esperar com o cabeçalho padrão [`Prefer: wait=N`](https://www.rfc-editor.org/rfc/rfc7240#section-4.3)
(segundos, limitado a **55**):

```bash theme={"dark"}
curl https://api.croma.run/co/policia/criminal-records/v1 \
  -H "Authorization: Bearer $CROMA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Prefer: wait=30" \
  -d '{ "document_number": "1234567890" }'
```

* **`200`**: terminou. O corpo é `{ "data": … }`, igual à forma síncrona.
* **`202`**: não terminou dentro do tempo de espera. O corpo é um [envelope de trabalho](#o-envelope-de-trabalho);
  siga seu `status_url` para fazer polling. O cabeçalho `X-Job-Id` carrega o id do trabalho.

<Note>
  Sempre trate tanto `200` quanto `202`. Um `202` não é um erro; significa
  apenas "ainda em andamento, volte para buscá-lo".
</Note>

***

## Modo 2: Polling

Envie `Prefer: wait=0` para obter um `202` imediatamente, depois faça `GET` no
`status_url` do trabalho até que ele alcance um estado terminal.

<CodeGroup>
  ```bash cURL theme={"dark"}
  # 1. Inicia el trabajo (devuelve 202 de inmediato)
  curl -i https://api.croma.run/co/policia/criminal-records/v1 \
    -H "Authorization: Bearer $CROMA_API_KEY" \
    -H "Content-Type: application/json" \
    -H "Prefer: wait=0" \
    -d '{ "document_number": "1234567890" }'

  # 2. Haz polling al status_url de la respuesta (o al encabezado Location)
  curl https://api.croma.run/jobs/run_abc123 \
    -H "Authorization: Bearer $CROMA_API_KEY"
  ```

  ```ts TypeScript theme={"dark"}
  // 1. Inicia el trabajo
  const start = await fetch(
    "https://api.croma.run/co/policia/criminal-records/v1",
    {
      method: "POST",
      headers: {
        Authorization: `Bearer ${process.env.CROMA_API_KEY}`,
        "Content-Type": "application/json",
        Prefer: "wait=0",
      },
      body: JSON.stringify({ document_number: "1234567890" }),
    },
  );
  const { job } = await start.json();

  // 2. Haz polling hasta el estado terminal
  async function poll(statusUrl: string) {
    while (true) {
      const res = await fetch(statusUrl, {
        headers: { Authorization: `Bearer ${process.env.CROMA_API_KEY}` },
      });
      const body = await res.json();
      if (body.job.status === "completed") return body.data;
      if (["failed", "canceled", "expired"].includes(body.job.status)) {
        throw new Error(body.error?.message ?? body.job.status);
      }
      // respeta Retry-After; por defecto 2s mientras se ejecuta
      const wait = Number(res.headers.get("Retry-After") ?? 2) * 1000;
      await new Promise((r) => setTimeout(r, wait));
    }
  }

  const data = await poll(job.status_url);
  ```
</CodeGroup>

`GET /jobs/:id` sempre retorna `200` com o [envelope](#o-envelope-de-trabalho).
Enquanto o trabalho ainda está em execução, inclui um cabeçalho `Retry-After`
(segundos); use-o para regular seu polling. Os trabalhos têm escopo da sua
organização; um trabalho que pertence a outra organização aparece como `404`.

***

## Modo 3: Callback (webhook)

Inclua um `callback_url` no corpo da solicitação. Você recebe um `202`
imediatamente, e o Croma faz `POST` com o resultado para a sua URL assim que o
trabalho termina, sem necessidade de polling.

<CodeGroup>
  ```bash cURL theme={"dark"}
  curl -i https://api.croma.run/co/policia/criminal-records/v1 \
    -H "Authorization: Bearer $CROMA_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
          "document_number": "1234567890",
          "callback_url": "https://your-app.com/webhooks/croma"
        }'
  ```

  ```ts TypeScript theme={"dark"}
  await fetch("https://api.croma.run/co/policia/criminal-records/v1", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.CROMA_API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      document_number: "1234567890",
      callback_url: "https://your-app.com/webhooks/croma",
    }),
  });
  // → 202. El resultado llega como un POST a tu callback_url.
  ```
</CodeGroup>

`callback_url` deve ser uma URL **HTTPS** absoluta em um host público (localhost
e as faixas privadas são rejeitados). Quando o trabalho termina, o Croma envia
um `POST` para ela:

* **Corpo**: o mesmo [envelope de trabalho](#o-envelope-de-trabalho) do endpoint de polling.
* **`x-croma-job-id`**: o id do trabalho.
* **`x-croma-signature`**: `sha256=<hmac>`, um HMAC-SHA256 do corpo bruto da
  solicitação, para que você possa verificar a integridade da carga útil.

```http theme={"dark"}
POST /webhooks/croma HTTP/1.1
content-type: application/json
x-croma-job-id: run_abc123
x-croma-signature: sha256=9f86d081…

{ "job": { "id": "run_abc123", "status": "completed", … }, "data": { … }, "error": null }
```

<Note>
  A verificação de assinatura usa um segredo compartilhado emitido pelo Croma;
  entre em contato conosco se quiser habilitá-la para seus callbacks. Responda
  `2xx` com rapidez; respostas diferentes de `2xx` provocam novas tentativas.
</Note>

***

## O envelope de trabalho

A resposta `202`, o `GET /jobs/:id` e o corpo do callback compartilham uma mesma
forma:

```json theme={"dark"}
{
  "job": {
    "id": "run_abc123",
    "status": "completed",
    "endpoint": "/co/policia/criminal-records/v1",
    "created_at": "2026-06-01T01:04:55.045Z",
    "finished_at": "2026-06-01T01:05:39.809Z",
    "status_url": "https://api.croma.run/jobs/run_abc123"
  },
  "data": { },
  "error": null
}
```

* **`data`** é preenchido apenas quando `status` é `completed` (e coincide com a
  carga útil `data` normal do endpoint). Caso contrário é `null`.
* **`error`** é preenchido apenas quando o trabalho falhou (`failed`), como
  `{ "type", "code", "message" }`.

### Estados

| `status`    | Terminal? | Significado                                |
| ----------- | --------- | ------------------------------------------ |
| `queued`    | não       | Aceito, aguardando execução.               |
| `running`   | não       | Em andamento.                              |
| `completed` | sim       | Pronto. Leia `data`.                       |
| `failed`    | sim       | O trabalho teve um erro. Leia `error`.     |
| `canceled`  | sim       | A execução foi cancelada.                  |
| `expired`   | sim       | A execução expirou antes de ser concluída. |

## Referência de cabeçalhos

| Cabeçalho                    | Onde                        | Significado                                                                                               |
| ---------------------------- | --------------------------- | --------------------------------------------------------------------------------------------------------- |
| `Prefer: wait=N`             | solicitação                 | Segundos de espera síncrona antes de retornar `202`. Limitado a 55. `wait=0` retorna `202` imediatamente. |
| `Preference-Applied: wait=N` | resposta `200`              | Reflete o tempo de espera que foi aplicado.                                                               |
| `Location`                   | resposta `202`              | O `status_url` do trabalho.                                                                               |
| `Retry-After`                | `202` / polling em execução | Segundos sugeridos antes de fazer polling novamente.                                                      |
| `X-Job-Id`                   | resposta `202` / `200`      | O id do trabalho.                                                                                         |

<Card title="Erros" icon="triangle-exclamation" href="/pt/errors">
  Como funcionam as falhas e o objeto `error`.
</Card>
