# Wait for evidence.  
Handle every outcome.

Most analysis POST endpoints return a queued job. Submission and completion are separate events: preserve the job ID, poll with a deadline, and branch on the terminal state.

## The job lifecycle

| Status | Meaning | Client action |
| --- | --- | --- |
| queued | Work accepted and waiting to run. | Keep the returned jobId. |
| processing | Analysis is running. | Poll again after a delay. |
| retrying | The service is retrying work. | Keep polling the same job within your deadline. |
| completed | Analysis finished successfully. | Read result and its limitations. |
| failed | Analysis ended with an error. | Stop; inspect the error and choose recovery. |

A status response can also include `phase`, `progress`, `attempt`, and `max_attempts`. Progress is informational; only a terminal status should release the next workflow step.

## Poll with a deadline

This Node.js example polls an existing job; it does not create another billable request. Set `AGENTSEO_API_KEY` and `AGENTSEO_JOB_ID` first. The 90-second deadline is an application choice, not a promised completion time.

Bounded Node.js polling example

```
const apiKey = process.env.AGENTSEO_API_KEY;
const jobId = process.env.AGENTSEO_JOB_ID;
if (!apiKey || !jobId) throw new Error("Set AGENTSEO_API_KEY and AGENTSEO_JOB_ID");
const deadline = Date.now() + 90_000;
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
let completed = false;
while (Date.now() < deadline) {
  const response = await fetch(
    "https://www.agentseo.dev/api/v1/jobs/" + encodeURIComponent(jobId),
    { headers: { "x-api-key": apiKey },
      signal: AbortSignal.timeout(Math.min(10_000, deadline - Date.now())) }
  );
  if (!response.ok) throw new Error("Polling HTTP " + response.status);
  const job = await response.json();
  if (job.status === "failed") {
    throw new Error(job.error?.code + ": " + job.error?.message);
  }
  if (job.status === "completed") {
    console.log(JSON.stringify(job.result, null, 2));
    completed = true;
    break;
  }
  await sleep(Math.min(2_000, Math.max(0, deadline - Date.now())));
}
if (!completed) throw new Error("Client deadline reached; save the job ID to resume later");
```

For submission, prefer the returned `retry_after_seconds` when present. On a polling HTTP error, this example stops and reports it. Add deliberate rate-limit and transient-error recovery for your application; do not retry every error indefinitely.

## Retry the right operation

-   **Still running:** poll the existing job. Resubmitting is different from checking status.
-   **Client deadline reached:** retain the ID and resume status checks later. A client timeout does not cancel server work.
-   **Terminal failure:** inspect `error.retryable` and the error code. A new submission may consume credits.
-   **Submission timeout:** for endpoints that support `Idempotency-Key`, reuse the same key for the same logical request. Use a new key for different work; do not reuse it with changed inputs.
-   **400, 401, 402, 403:** fix the input, key, credits, or policy before repeating a request.

Preserve request IDs for support. Keep API keys and private page content out of logs.

## Inline waits, events, and exceptions

`?sync=true` on supported endpoints opens a short processing window. It can still return `202`, so keep your job handling even in synchronous-looking code.

[Job events](https://www.agentseo.dev/docs/api-reference/system#get-jobs-id-events) provide an authenticated server-sent event stream. Browser-native EventSource cannot attach an arbitrary API-key header; use a server-side client or an authenticated fetch-stream implementation.

`/extract` and webhook management are synchronous. `/audit/local/batch` returns multiple job IDs. Check each endpoint’s contract instead of assuming every POST uses the same response shape.

[Jobs and webhooks reference](https://www.agentseo.dev/docs/api-reference/system) · [Error recovery](https://www.agentseo.dev/docs/errors) · [SDK helpers](https://www.agentseo.dev/docs/sdks)

---
Canonical HTML: https://www.agentseo.dev/docs/async-jobs
Markdown: https://www.agentseo.dev/docs/async-jobs/index.md
