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

# Search lifecycle

> Understand asynchronous jobs, live result delivery, dashboard sync, and safe polling.

## State sequence

```text theme={null}
queued → starting → running → importing → enriching → completed
                                                    ↘ failed
```

The exact active sequence can skip states when work finishes quickly. Treat only `completed` and `failed` as terminal.

Standalone enrichment skips discovery and begins at `enriching`:

```text theme={null}
enriching → completed
          ↘ failed
```

| Status | Meaning |
| - | - |
| `queued` | The durable job exists and is waiting for worker capacity. |
| `starting` | Mapsdata is starting business discovery. |
| `running` | Discovery is active and can already produce businesses. |
| `importing` | Remaining discovered rows are being committed. |
| `enriching` | Contact and verification stages are processing imported businesses. |
| `completed` | Discovery and enabled enrichment stages finished successfully. |
| `failed` | The job ended unsuccessfully. Any rows imported before failure remain available. |

## Live results

The worker commits every available batch rather than waiting for the provider run to finish. Each commit updates `lead_count`, and `GET /searches/{search_id}/results` immediately exposes those rows.

The web app reads the same job and lead records. API-created searches and standalone enrichments therefore:

* appear in Dashboard and Lead lists with an **API** origin label;
* update status and lead counts while processing;
* show newly found businesses in the result table before completion;
* use the same plan, credit balance, active-job allowance, and workers as UI searches.

Use the matching endpoint family when polling: `/searches/{id}` for discovery jobs and `/enrichments/{id}` for supplied-business jobs.

## Recommended polling loop

<Steps>
  <Step title="Store the job ID">Persist `job_id` from the `202 Accepted` response.</Step>
  <Step title="Poll every 5–10 seconds">Read the job status and, when live display matters, page 1 of results.</Step>
  <Step title="Honor rate-limit headers">On `429`, wait for `Retry-After` and add jitter before retrying.</Step>
  <Step title="Re-read after terminal status">Fetch results again from page 1 because enrichment fields can change while a job is active.</Step>
  <Step title="Finish pagination">Continue until `has_more=false` and verify the accumulated item count equals `total`.</Step>
</Steps>

Do not create a replacement job merely because polling timed out. Resume from the stored `job_id`, or retry creation with the original body and original `Idempotency-Key`.
